Version 1.17.0-dev.0.0
Merge a47eb0f59e5fb8e59cc9cb994fecd7f474c16018 into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af5ee69..b247533 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,109 @@
-## 1.16.0
+## 1.17.0
+
+### Core library changes
+* `dart:core`
+ * `Uri.replace` supports iterables as values for the query parameters.
+ * `Uri.parseIPv6Address` returns a `Uint8List`.
+
+* `dart:io`
+ * Added `NetworkInterface.listSupported`, which is `true` when
+ `NetworkInterface.list` is supported, and `false` otherwise. Currently,
+ `NetworkInterface.list` is not supported on Android.
+
+## 1.16.0 - 2016-04-26
### Core library changes
* `dart:convert`
* Added `BASE64URL` codec and corresponding `Base64Codec.urlSafe` constructor.
+
+ * Introduce `ChunkedConverter` and deprecate chunked methods on `Converter`.
+
+* `dart:html`
+
+ There have been a number of **BREAKING** changes to align APIs with recent
+ changes in Chrome. These include:
+
+ * Chrome's `ShadowRoot` interface no longer has the methods `getElementById`,
+ `getElementsByClassName`, and `getElementsByTagName`, e.g.,
+
+ ```dart
+ elem.shadowRoot.getElementsByClassName('clazz')
+ ```
+
+ should become:
+
+ ```dart
+ elem.shadowRoot.querySelectorAll('.clazz')
+ ```
+
+ * The `clipboardData` property has been removed from `KeyEvent`
+ and `Event`. It has been moved to the new `ClipboardEvent` class, which is
+ now used by `copy`, `cut`, and `paste` events.
+
+ * The `layer` property has been removed from `KeyEvent` and
+ `UIEvent`. It has been moved to `MouseEvent`.
+
+ * The `Point get page` property has been removed from `UIEvent`.
+ It still exists on `MouseEvent` and `Touch`.
+
+ There have also been a number of other additions and removals to `dart:html`,
+ `dart:indexed_db`, `dart:svg`, `dart:web_audio`, and `dart:web_gl` that
+ correspond to changes to Chrome APIs between v39 and v45. Many of the breaking
+ changes represent APIs that would have caused runtime exceptions when compiled
+ to Javascript and run on recent Chrome releases.
+
* `dart:io`
* Added `SecurityContext.alpnSupported`, which is true if a platform
supports ALPN, and false otherwise.
-* `dart:convert`
- * Introduce `ChunkedConverter` and deprecate chunked methods on `Converter`.
+### JavaScript interop
+
+For performance reasons, a potentially **BREAKING** change was added for
+libraries that use JS interop.
+Any Dart file that uses `@JS` annotations on declarations (top-level functions,
+classes or class members) to interop with JavaScript code will require that the
+file have the annotation `@JS()` on a library directive.
+
+```dart
+@JS()
+library my_library;
+```
+
+The analyzer will enforce this by generating the error:
+
+The `@JS()` annotation can only be used if it is also declared on the library
+directive.
+
+If part file uses the `@JS()` annotation, the library that uses the part should
+have the `@JS()` annotation e.g.,
+
+```dart
+// library_1.dart
+@JS()
+library library_1;
+
+import 'package:js/js.dart';
+
+part 'part_1.dart';
+```
+
+```dart
+// part_1.dart
+part of library_1;
+
+@JS("frameworkStabilizers")
+external List<FrameworkStabilizer> get frameworkStabilizers;
+```
+
+If your library already has a JS module e.g.,
+
+```dart
+@JS('array.utils')
+library my_library;
+```
+
+Then your library will work without any additional changes.
### Analyzer
diff --git a/DEPS b/DEPS
index 1f50fd4..c4bf8bb 100644
--- a/DEPS
+++ b/DEPS
@@ -31,7 +31,11 @@
# Revisions of /third_party/* dependencies.
"args_tag": "@0.13.4",
"async_tag": "@1.9.0",
+ "barback-0.13.0_rev": "@34853",
+ "barback-0.14.0_rev": "@36398",
+ "barback-0.14.1_rev": "@38525",
"barback_tag" : "@0.15.2+7",
+ "bazel_worker_tag": "@v0.1.0",
"boolean_selector_tag" : "@1.0.0",
"boringssl_rev" : "@daeafc22c66ad48f6b32fc8d3362eb9ba31b774e",
"charcode_tag": "@1.1.0",
@@ -39,24 +43,26 @@
"cli_util_tag" : "@0.0.1+2",
"collection_rev": "@f6135e6350c63eb3f4dd12953b8d4363faff16fc",
"convert_tag": "@1.0.0",
- "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
+ "crypto_tag" : "@1.1.0",
"csslib_tag" : "@0.12.0",
"dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
- "dartdoc_tag" : "@v0.9.0",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
"dart_style_tag": "@0.2.4",
- "dev_compiler_rev": "@0c5dd2d1e999c421d978a478e267aac6279e087a",
+ "dartdoc_tag" : "@v0.9.0",
+ "dev_compiler_rev": "@0ed6aeca35fa0e618ad0f7f19f3eba64afdd80c4",
+ "fixnum_tag": "@0.10.4",
+ "func_rev": "@8d4aea75c21be2179cb00dc2b94a71414653094e",
"glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
"html_tag" : "@0.12.1+1",
- "http_tag" : "@0.11.3+3",
"http_multi_server_tag" : "@2.0.0",
"http_parser_tag" : "@1.1.0",
+ "http_tag" : "@0.11.3+3",
"http_throttle_rev" : "@a81f08be942cdd608883c7b67795c12226abc235",
"idl_parser_rev": "@7fbe68cab90c38147dee4f48c30ad0d496c17915",
"intl_rev": "@a8b480b9c436f6c0ec16730804c914bdb4e30d53",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "@2.0.0",
- "linter_rev": "@bcd4cf615665a80edf3f9a924388e59644a667cd",
+ "linter_rev": "@6d3bdf09b4326a411e44ff472953edd9003bc33a",
"logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
"markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
"matcher_tag": "@0.12.0",
@@ -64,49 +70,46 @@
"mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
"mustache4dart_rev" : "@5724cfd85151e5b6b53ddcd3380daf188fe47f92",
"oauth2_tag": "@1.0.0",
- "observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
"observatory_pub_packages_rev": "@cf90eb9077177d3d6b3fd5e8289477c2385c026a",
+ "observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
"package_config_rev": "@0.1.3",
"path_tag": "@1.3.6",
- "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"plugin_tag": "@0.1.0",
+ "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_tag": "@1.2.1",
- "protobuf_tag": "@0.5.0+1",
- "pub_rev": "@04ff0cc2cb6a3b698159b1aeef14cd3d7c90e287",
+ "protobuf_tag": "@0.5.1+1",
"pub_cache_tag": "@v0.1.0",
+ "pub_rev": "@217fc8ae2bdee58ebf4b11a6fa3d49624d90c0c4",
"pub_semver_tag": "@1.2.1",
"quiver_tag": "@0.21.4",
"resource_rev":"@a49101ba2deb29c728acba6fb86000a8f730f4b1",
"root_certificates_rev": "@aed07942ce98507d2be28cbd29e879525410c7fc",
"scheduled_test_tag": "@0.12.5+2",
- "shelf_tag": "@0.6.5",
- "smoke_rev" : "@f3361191cc2a85ebc1e4d4c33aec672d7915aba9",
- "source_maps_tag": "@0.10.1",
"shelf_static_tag": "@0.2.3+1",
+ "shelf_tag": "@0.6.5",
"shelf_web_socket_tag": "@0.2.0",
+ "smoke_rev" : "@f3361191cc2a85ebc1e4d4c33aec672d7915aba9",
"source_map_stack_trace_tag": "@1.0.4",
+ "source_maps-0.9.4_rev": "@38524",
+ "source_maps_tag": "@0.10.1",
"source_span_tag": "@1.2.0",
"stack_trace_tag": "@1.4.2",
"stream_channel_tag": "@1.3.1",
"string_scanner_tag": "@0.1.4",
"sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
- "test_tag": "@0.12.12",
"test_reflective_loader_tag": "@0.0.3",
+ "test_tag": "@0.12.12",
"typed_data_tag": "@1.1.2",
- "utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
"usage_rev": "@b5080dac0d26a5609b266f8fdb0d053bc4c1c638",
+ "utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
"watcher_tag": "@0.9.7",
- "when_tag": "@0.2.0+2",
- "which_tag": "@0.1.3+1",
"web_components_rev": "@6349e09f9118dce7ae1b309af5763745e25a9d61",
"web_socket_channel_tag": "@1.0.0",
"WebCore_rev": "@a86fe28efadcfc781f836037a80f27e22a5dad17",
+ "when_tag": "@0.2.0+2",
+ "which_tag": "@0.1.3+1",
"yaml_tag": "@2.1.5",
"zlib_rev": "@c3d0a6190f2f8c924a05ab6cc97b8f975bddd33f",
- "barback-0.13.0_rev": "@34853",
- "barback-0.14.0_rev": "@36398",
- "barback-0.14.1_rev": "@38525",
- "source_maps-0.9.4_rev": "@38524",
}
deps = {
@@ -150,6 +153,8 @@
(Var("github_mirror") % "async") + Var("async_tag"),
Var("dart_root") + "/third_party/pkg/barback":
(Var("github_mirror") % "barback") + Var("barback_tag"),
+ Var("dart_root") + "/third_party/pkg/bazel_worker":
+ (Var("github_dartlang") % "bazel_worker") + Var("bazel_worker_tag"),
Var("dart_root") + "/third_party/pkg/boolean_selector":
(Var("github_dartlang") % "boolean_selector") +
Var("boolean_selector_tag"),
@@ -162,7 +167,7 @@
Var("dart_root") + "/third_party/pkg/convert":
"https://github.com/dart-lang/convert.git" + Var("convert_tag"),
Var("dart_root") + "/third_party/pkg/crypto":
- (Var("github_mirror") % "crypto") + Var("crypto_rev"),
+ (Var("github_mirror") % "crypto") + Var("crypto_tag"),
Var("dart_root") + "/third_party/pkg/csslib":
(Var("github_mirror") % "csslib") + Var("csslib_tag"),
Var("dart_root") + "/third_party/dart-services":
@@ -176,6 +181,10 @@
(Var("github_mirror") % "dartdoc") + Var("dartdoc_tag"),
Var("dart_root") + "/third_party/pkg/dev_compiler":
(Var("github_mirror") % "dev_compiler") + Var("dev_compiler_rev"),
+ Var("dart_root") + "/third_party/pkg/func":
+ (Var("github_dartlang") % "func") + Var("func_rev"),
+ Var("dart_root") + "/third_party/pkg/fixnum":
+ "https://github.com/dart-lang/fixnum.git" + Var("fixnum_tag"),
Var("dart_root") + "/third_party/pkg/glob":
(Var("github_mirror") % "glob") + Var("glob_rev"),
Var("dart_root") + "/third_party/pkg/html":
diff --git a/dart.gyp b/dart.gyp
index b8d3e43f..b942371 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -26,9 +26,35 @@
'type': 'none',
'dependencies': [
'runtime/dart-runtime.gyp:dart',
- 'runtime/dart-runtime.gyp:dart_noopt',
+ 'runtime/dart-runtime.gyp:dart_bootstrap#host',
+ 'runtime/dart-runtime.gyp:run_vm_tests',
+ 'runtime/dart-runtime.gyp:process_test',
+ 'packages',
+ 'runtime/dart-runtime.gyp:test_extension',
+ 'runtime/dart-runtime.gyp:sample_extension',
+ ],
+ },
+ {
+ # This is the target that is built on the VM build bots. It
+ # must depend on anything that is required by the VM test
+ # suites.
+ 'target_name': 'runtime_precompiled',
+ 'type': 'none',
+ 'dependencies': [
'runtime/dart-runtime.gyp:dart_precompiled_runtime',
- 'runtime/dart-runtime.gyp:dart_product',
+ 'runtime/dart-runtime.gyp:dart_bootstrap#host',
+ 'packages',
+ ],
+ },
+ {
+ # This is the target that is built on the VM build bots. It
+ # must depend on anything that is required by the VM test
+ # suites.
+ 'target_name': 'runtime_and_noopt',
+ 'type': 'none',
+ 'dependencies': [
+ 'runtime/dart-runtime.gyp:dart',
+ 'runtime/dart-runtime.gyp:dart_noopt',
'runtime/dart-runtime.gyp:dart_bootstrap#host',
'runtime/dart-runtime.gyp:run_vm_tests',
'runtime/dart-runtime.gyp:process_test',
diff --git a/pkg/analysis_server/lib/plugin/analysis/navigation/navigation_core.dart b/pkg/analysis_server/lib/plugin/analysis/navigation/navigation_core.dart
index dea288b..52eb74c 100644
--- a/pkg/analysis_server/lib/plugin/analysis/navigation/navigation_core.dart
+++ b/pkg/analysis_server/lib/plugin/analysis/navigation/navigation_core.dart
@@ -5,7 +5,7 @@
library analysis_server.plugin.analysis.navigation.navigation_core;
import 'package:analysis_server/plugin/protocol/protocol.dart'
- show ElementKind, Location, NavigationRegion, NavigationTarget;
+ show ElementKind, Location;
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/source.dart' show Source;
diff --git a/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart b/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart
index ac56afd..cab96a9 100644
--- a/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart
+++ b/pkg/analysis_server/lib/plugin/analysis/occurrences/occurrences_core.dart
@@ -4,8 +4,7 @@
library analysis_server.plugin.analysis.occurrences.occurrences_core;
-import 'package:analysis_server/plugin/protocol/protocol.dart'
- show Element, Occurrences;
+import 'package:analysis_server/plugin/protocol/protocol.dart' show Occurrences;
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/source.dart' show Source;
diff --git a/pkg/analysis_server/lib/src/analysis_manager.dart b/pkg/analysis_server/lib/src/analysis_manager.dart
index 2e9924c..126dbb8 100644
--- a/pkg/analysis_server/lib/src/analysis_manager.dart
+++ b/pkg/analysis_server/lib/src/analysis_manager.dart
@@ -36,11 +36,12 @@
* Otherwise there was no attached process or the signal could not be sent,
* usually meaning that the process is already dead.
*/
- Future<bool> stop() {
+ Future<bool> stop() async {
if (process == null) {
- return channel.close().then((_) => false);
+ await channel.close();
+ return false;
}
- return channel
+ int result = await channel
.sendRequest(new ServerShutdownParams().toRequest('0'))
.timeout(new Duration(seconds: 2), onTimeout: () {
print('Expected shutdown response');
@@ -49,12 +50,11 @@
}).timeout(new Duration(seconds: 2), onTimeout: () {
print('Expected server to shutdown');
process.kill();
- }).then((int result) {
- if (result != null && result != 0) {
- exitCode = result;
- }
- return true;
});
+ if (result != null && result != 0) {
+ exitCode = result;
+ }
+ return true;
}
/**
@@ -102,7 +102,7 @@
/**
* Open a connection to the analysis server using the given URL.
*/
- Future<AnalysisManager> _openConnection(String serverUrl) {
+ Future<AnalysisManager> _openConnection(String serverUrl) async {
Function onError = (error) {
exitCode = 1;
if (process != null) {
@@ -111,13 +111,9 @@
throw 'Failed to connect to analysis server at $serverUrl\n $error';
};
try {
- return WebSocket
- .connect(serverUrl)
- .catchError(onError)
- .then((WebSocket socket) {
- this.channel = new WebSocketClientChannel(socket);
- return this;
- });
+ WebSocket socket = await WebSocket.connect(serverUrl).catchError(onError);
+ this.channel = new WebSocketClientChannel(socket);
+ return this;
} catch (error) {
onError(error);
}
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 6bda5f9..5a06a6e 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -22,6 +22,7 @@
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
+import 'package:analysis_server/src/single_context_manager.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -312,8 +313,9 @@
this.options,
this.defaultSdkCreator,
this.instrumentationService,
- {ResolverProvider packageResolverProvider: null,
- EmbeddedResolverProvider embeddedResolverProvider: null,
+ {EmbeddedResolverProvider embeddedResolverProvider: null,
+ ResolverProvider packageResolverProvider: null,
+ bool useSingleContextManager: false,
this.rethrowExceptions: true})
: index = _index,
searchEngine = _index != null ? new SearchEngineImpl(_index) : null {
@@ -326,15 +328,20 @@
defaultContextOptions.generateImplicitErrors = false;
operationQueue = new ServerOperationQueue();
sdkManager = new DartSdkManager(defaultSdkCreator);
- contextManager = new ContextManagerImpl(
- resourceProvider,
- sdkManager,
- packageResolverProvider,
- embeddedResolverProvider,
- packageMapProvider,
- analyzedFilesGlobs,
- instrumentationService,
- defaultContextOptions);
+ if (useSingleContextManager) {
+ contextManager = new SingleContextManager(resourceProvider, sdkManager,
+ () => packageResolverProvider(null), analyzedFilesGlobs);
+ } else {
+ contextManager = new ContextManagerImpl(
+ resourceProvider,
+ sdkManager,
+ packageResolverProvider,
+ embeddedResolverProvider,
+ packageMapProvider,
+ analyzedFilesGlobs,
+ instrumentationService,
+ defaultContextOptions);
+ }
ServerContextManagerCallbacks contextManagerCallbacks =
new ServerContextManagerCallbacks(this, resourceProvider);
contextManager.callbacks = contextManagerCallbacks;
@@ -1583,6 +1590,13 @@
analysisServer._computingPackageMap(computing);
@override
+ void moveContext(Folder from, Folder to) {
+ // There is nothing to do.
+ // This method is mostly for tests.
+ // Context managers manage folders and contexts themselves.
+ }
+
+ @override
void removeContext(Folder folder, List<String> flushedFiles) {
AnalysisContext context = analysisServer.folderMap.remove(folder);
sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 3afe0f2..a87fdc5 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -335,6 +335,12 @@
void computingPackageMap(bool computing);
/**
+ * Called when the context manager changes the folder with which a context is
+ * associated. Currently this is mostly FYI, and used only in tests.
+ */
+ void moveContext(Folder from, Folder to);
+
+ /**
* Remove the context associated with the given [folder]. [flushedFiles] is
* a list of the files which will be "orphaned" by removing this context
* (they will no longer be analyzed by any context).
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index df307fb..6dc2c43 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -14,10 +14,7 @@
import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/domains/analysis/navigation.dart';
import 'package:analysis_server/src/operation/operation_analysis.dart'
- show
- NavigationOperation,
- OccurrencesOperation,
- sendAnalysisNotificationNavigation;
+ show NavigationOperation, OccurrencesOperation;
import 'package:analysis_server/src/protocol/protocol_internal.dart';
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
index 6bdf510..97a162e 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -20,6 +20,7 @@
const int DART_RELEVANCE_COMMON_USAGE = 1200;
const int DART_RELEVANCE_DEFAULT = 1000;
const int DART_RELEVANCE_HIGH = 2000;
+const int DART_RELEVANCE_INCREMENT = 20;
const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
const int DART_RELEVANCE_INHERITED_FIELD = 1058;
const int DART_RELEVANCE_INHERITED_METHOD = 1057;
@@ -114,7 +115,17 @@
* Any information obtained from [target] prior to calling this method
* should be discarded as it may have changed.
*/
- Future resolveExpression(Expression expression);
+ Future resolveContainingExpression(AstNode node);
+
+ /**
+ * Return a [Future] that completes when the element associated with
+ * the given [statement] in the target compilation unit is available.
+ * It may also complete if the statement cannot be resolved
+ * (e.g. unknown identifier, completion aborted, etc).
+ * Any information obtained from [target] prior to calling this method
+ * should be discarded as it may have changed.
+ */
+ Future resolveContainingStatement(AstNode node);
/**
* Return a [Future] that completes with a list of [ImportElement]s
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
index ea6b489..cf34c94 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
@@ -24,6 +24,7 @@
import 'package:analysis_server/src/services/completion/dart/static_member_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/type_member_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/uri_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/variable_name_contributor.dart';
import 'package:plugin/plugin.dart';
/**
@@ -115,6 +116,8 @@
() => new TypeMemberContributor());
registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
() => new UriContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new VariableNameContributor());
}
/**
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index 74c72ef..30ae422 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -64,12 +64,10 @@
/**
* Returns a [Future] completing with a [List] of references to [element].
*/
- Future<List<SearchResult>> _findSingleElementReferences(Element element) {
- Future<List<SearchMatch>> matchesFuture =
- searchEngine.searchReferences(element);
- return matchesFuture.then((List<SearchMatch> matches) {
- return matches.map(toResult).toList();
- });
+ Future<List<SearchResult>> _findSingleElementReferences(
+ Element element) async {
+ List<SearchMatch> matches = await searchEngine.searchReferences(element);
+ return matches.map(toResult).toList();
}
/**
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index f04824f..a5af1b22 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -310,6 +310,14 @@
ResolverProvider packageResolverProvider;
/**
+ * If this flag is `true`, then single analysis context should be used for
+ * analysis of multiple analysis roots, special files that could otherwise
+ * cause creating additional contexts, such as `pubspec.yaml`, or `.packages`,
+ * or `.analysis_options` are ignored.
+ */
+ bool useSingleContextManager = false;
+
+ /**
* The plugins that are defined outside the analysis_server package.
*/
List<Plugin> _userDefinedPlugins = <Plugin>[];
@@ -436,8 +444,9 @@
defaultSdk,
service,
serverPlugin,
+ embeddedUriResolverProvider,
packageResolverProvider,
- embeddedUriResolverProvider);
+ useSingleContextManager);
httpServer = new HttpAnalysisServer(socketServer);
stdioServer = new StdioAnalysisServer(socketServer);
socketServer.userDefinedPlugins = _userDefinedPlugins;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index 54529b8..f29e7a6 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -181,7 +181,7 @@
}
// Resolve the target expression to determine the arguments
- await request.resolveExpression(targetId);
+ await request.resolveContainingExpression(targetId);
// Gracefully degrade if the element could not be resolved
// e.g. target changed, completion aborted
targetId = _getTargetId(request.target.containingNode);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 21ba3c7..7be86e4 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -23,10 +23,9 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/context.dart'
- show AnalysisFutureHelper, AnalysisContextImpl;
+import 'package:analyzer/src/context/context.dart' show AnalysisFutureHelper;
import 'package:analyzer/src/dart/ast/token.dart';
-import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/dart.dart';
@@ -226,11 +225,24 @@
}
@override
- Future resolveExpression(Expression expression) async {
+ Future resolveContainingExpression(AstNode node) async {
+ // TODO When an Expression can be resolved instead of just an entire unit,
+ // this will be revisited with code searching up the parent until an
+ // Expression is found.
+
+ return resolveContainingStatement(node);
+ }
+
+ @override
+ Future resolveContainingStatement(AstNode node) async {
+ // TODO When a Statement can be resolved instead of just an entire unit,
+ // this will be revisited with code searching up the parent until a
+ // Statement is found.
+
checkAborted();
// Return immediately if the expression has already been resolved
- if (expression.propagatedType != null) {
+ if (node is Expression && node.propagatedType != null) {
return;
}
@@ -241,7 +253,7 @@
// Resolve declarations in the target unit
// TODO(danrubel) resolve the expression or containing method
- // rather than the entire complilation unit
+ // rather than the entire compilation unit
CompilationUnit resolvedUnit = await _computeAsync(
this,
new LibrarySpecificUnit(librarySource, source),
@@ -400,7 +412,7 @@
if (node is Expression) {
const FUNCTIONAL_ARG_TAG = 'resolve expression for isFunctionalArg';
performance.logStartTime(FUNCTIONAL_ARG_TAG);
- await dartRequest.resolveExpression(node);
+ await dartRequest.resolveContainingExpression(node);
performance.logElapseTime(FUNCTIONAL_ARG_TAG);
dartRequest.checkAborted();
}
@@ -472,18 +484,15 @@
}
if (token is StringToken) {
SimpleStringLiteral uri = new SimpleStringLiteral(token, token.lexeme);
- Token previous = token.previous;
- if (previous is KeywordToken) {
- Keyword keyword = previous.keyword;
- if (keyword == Keyword.IMPORT ||
- keyword == Keyword.EXPORT ||
- keyword == Keyword.PART) {
- int start = uri.contentsOffset;
- var end = uri.contentsEnd;
- if (start <= requestOffset && requestOffset <= end) {
- // Replacement range for import URI
- return new ReplacementRange(start, end - start);
- }
+ Keyword keyword = token.previous?.keyword;
+ if (keyword == Keyword.IMPORT ||
+ keyword == Keyword.EXPORT ||
+ keyword == Keyword.PART) {
+ int start = uri.contentsOffset;
+ var end = uri.contentsEnd;
+ if (start <= requestOffset && requestOffset <= end) {
+ // Replacement range for import URI
+ return new ReplacementRange(start, end - start);
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
index 43514fb..62bda0c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
@@ -36,6 +36,10 @@
// Compute the list of fields already referenced in the constructor
List<String> referencedFields = new List<String>();
for (FormalParameter param in constructorDecl.parameters.parameters) {
+ if (param is DefaultFormalParameter &&
+ param.parameter is FieldFormalParameter) {
+ param = (param as DefaultFormalParameter).parameter;
+ }
if (param is FieldFormalParameter) {
SimpleIdentifier fieldId = param.identifier;
if (fieldId != null && fieldId != request.target.entity) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
index 4651491..89dd436 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
@@ -14,8 +14,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/resolver.dart';
-import '../../../protocol_server.dart'
- show CompletionSuggestion, CompletionSuggestionKind;
+import '../../../protocol_server.dart' show CompletionSuggestion;
List<String> hiddenNamesIn(ImportElement importElem) {
for (NamespaceCombinator combinator in importElem.combinators) {
@@ -58,10 +57,7 @@
// then resolve the outermost/entire expression
AstNode node = request.target.containingNode;
if (node is Expression) {
- while (node.parent is Expression) {
- node = node.parent;
- }
- await request.resolveExpression(node);
+ await request.resolveContainingExpression(node);
// Discard any cached target information
// because it may have changed as a result of the resolution
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
index 4587864..12692c0 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -28,7 +28,7 @@
}
// Resolve the expression and the containing library
- await request.resolveExpression(request.dotTarget);
+ await request.resolveContainingExpression(request.dotTarget);
// Recompute the target since resolution may have changed it
Expression targetId = request.dotTarget;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
index eb527a4..8778f6c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
@@ -165,8 +165,16 @@
List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
if (!optype.isPrefixed) {
if (optype.includeConstructorSuggestions) {
- _Visitor visitor = new _Visitor(request, suggestions);
- visitor.visit(request.target.containingNode);
+ AstNode node = request.target.containingNode;
+
+ await request.resolveContainingStatement(node);
+
+ // Discard any cached target information
+ // because it may have changed as a result of the resolution
+ node = request.target.containingNode;
+
+ _Visitor visitor = new _Visitor(request, suggestions, optype);
+ visitor.visit(node);
}
}
return suggestions;
@@ -178,9 +186,10 @@
*/
class _Visitor extends LocalDeclarationVisitor {
final DartCompletionRequest request;
+ final OpType optype;
final List<CompletionSuggestion> suggestions;
- _Visitor(DartCompletionRequest request, this.suggestions)
+ _Visitor(DartCompletionRequest request, this.suggestions, this.optype)
: request = request,
super(request.offset);
@@ -237,6 +246,12 @@
String completion = classDecl.name.name;
SimpleIdentifier elemId;
+ int relevance = optype.constructorSuggestionsFilter(
+ classDecl.element?.type, DART_RELEVANCE_DEFAULT);
+ if (relevance == null) {
+ return;
+ }
+
// Build a suggestion for explicitly declared constructor
if (constructorDecl != null) {
elemId = constructorDecl.name;
@@ -248,8 +263,8 @@
}
}
if (elem != null) {
- CompletionSuggestion suggestion =
- createSuggestion(elem, completion: completion);
+ CompletionSuggestion suggestion = createSuggestion(elem,
+ completion: completion, relevance: relevance);
if (suggestion != null) {
suggestions.add(suggestion);
}
@@ -264,7 +279,7 @@
element.returnType = classDecl.name.name;
CompletionSuggestion suggestion = new CompletionSuggestion(
CompletionSuggestionKind.INVOCATION,
- DART_RELEVANCE_DEFAULT,
+ relevance,
completion,
completion.length,
0,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
index 68beb6a..5c10beb 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/services/completion/dart/optype.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
show createSuggestion, ElementSuggestionBuilder;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
@@ -45,13 +46,18 @@
void visitClassElement(ClassElement element) {
if (optype.includeTypeNameSuggestions) {
// if includeTypeNameSuggestions, then use the filter
- if (optype.typeNameSuggestionsFilter(element.type)) {
- addSuggestion(element,
- prefix: prefix, relevance: DART_RELEVANCE_DEFAULT);
+ int relevance = optype.typeNameSuggestionsFilter(
+ element.type, DART_RELEVANCE_DEFAULT);
+ if (relevance != null) {
+ addSuggestion(element, prefix: prefix, relevance: relevance);
}
}
if (optype.includeConstructorSuggestions) {
- _addConstructorSuggestions(element, DART_RELEVANCE_DEFAULT);
+ int relevance = optype.constructorSuggestionsFilter(
+ element.type, DART_RELEVANCE_DEFAULT);
+ if (relevance != null) {
+ _addConstructorSuggestions(element, relevance);
+ }
}
}
@@ -171,6 +177,16 @@
return EMPTY_LIST;
}
+ AstNode node = request.target.containingNode;
+
+ // If the target is in an expression
+ // then resolve the outermost/entire expression
+ await request.resolveContainingExpression(node);
+
+ // Discard any cached target information
+ // because it may have changed as a result of the resolution
+ node = request.target.containingNode;
+
OpType optype = (request as DartCompletionRequestImpl).opType;
LibraryElementSuggestionBuilder visitor =
new LibraryElementSuggestionBuilder(request, optype);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index 8d613ce..750e623 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -160,11 +160,9 @@
// If the target is in an expression
// then resolve the outermost/entire expression
AstNode node = request.target.containingNode;
+
if (node is Expression) {
- while (node.parent is Expression) {
- node = node.parent;
- }
- await request.resolveExpression(node);
+ await request.resolveContainingExpression(node);
// Discard any cached target information
// because it may have changed as a result of the resolution
@@ -236,7 +234,7 @@
@override
void declaredClass(ClassDeclaration declaration) {
if (optype.includeTypeNameSuggestions) {
- _addLocalSuggestion(
+ _addLocalSuggestion_includeTypeNameSuggestions(
declaration.name, NO_RETURN_TYPE, protocol.ElementKind.CLASS,
isAbstract: declaration.isAbstract,
isDeprecated: _isDeprecated(declaration));
@@ -246,8 +244,8 @@
@override
void declaredClassTypeAlias(ClassTypeAlias declaration) {
if (optype.includeTypeNameSuggestions) {
- _addLocalSuggestion(declaration.name, NO_RETURN_TYPE,
- protocol.ElementKind.CLASS_TYPE_ALIAS,
+ _addLocalSuggestion_includeTypeNameSuggestions(declaration.name,
+ NO_RETURN_TYPE, protocol.ElementKind.CLASS_TYPE_ALIAS,
isAbstract: true, isDeprecated: _isDeprecated(declaration));
}
}
@@ -255,7 +253,7 @@
@override
void declaredEnum(EnumDeclaration declaration) {
if (optype.includeTypeNameSuggestions) {
- _addLocalSuggestion(
+ _addLocalSuggestion_includeTypeNameSuggestions(
declaration.name, NO_RETURN_TYPE, protocol.ElementKind.ENUM,
isDeprecated: _isDeprecated(declaration));
}
@@ -267,7 +265,8 @@
(!optype.inStaticMethodBody || fieldDecl.isStatic)) {
bool deprecated = _isDeprecated(fieldDecl) || _isDeprecated(varDecl);
TypeName typeName = fieldDecl.fields.type;
- _addLocalSuggestion(varDecl.name, typeName, protocol.ElementKind.FIELD,
+ _addLocalSuggestion_includeReturnValueSuggestions(
+ varDecl.name, typeName, protocol.ElementKind.FIELD,
isDeprecated: deprecated,
relevance: DART_RELEVANCE_LOCAL_FIELD,
classDecl: fieldDecl.parent);
@@ -298,7 +297,8 @@
elemKind = protocol.ElementKind.FUNCTION;
relevance = DART_RELEVANCE_LOCAL_FUNCTION;
}
- _addLocalSuggestion(declaration.name, typeName, elemKind,
+ _addLocalSuggestion_includeReturnValueSuggestions(
+ declaration.name, typeName, elemKind,
isDeprecated: _isDeprecated(declaration),
param: declaration.functionExpression.parameters,
relevance: relevance);
@@ -309,8 +309,8 @@
void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {
if (optype.includeTypeNameSuggestions) {
// TODO (danrubel) determine parameters and return type
- _addLocalSuggestion(declaration.name, declaration.returnType,
- protocol.ElementKind.FUNCTION_TYPE_ALIAS,
+ _addLocalSuggestion_includeTypeNameSuggestions(declaration.name,
+ declaration.returnType, protocol.ElementKind.FUNCTION_TYPE_ALIAS,
isAbstract: true, isDeprecated: _isDeprecated(declaration));
}
}
@@ -323,7 +323,8 @@
@override
void declaredLocalVar(SimpleIdentifier id, TypeName typeName) {
if (optype.includeReturnValueSuggestions) {
- _addLocalSuggestion(id, typeName, protocol.ElementKind.LOCAL_VARIABLE,
+ _addLocalSuggestion_includeReturnValueSuggestions(
+ id, typeName, protocol.ElementKind.LOCAL_VARIABLE,
relevance: DART_RELEVANCE_LOCAL_VARIABLE);
}
}
@@ -356,7 +357,8 @@
param = declaration.parameters;
relevance = DART_RELEVANCE_LOCAL_METHOD;
}
- _addLocalSuggestion(declaration.name, typeName, elemKind,
+ _addLocalSuggestion_includeReturnValueSuggestions(
+ declaration.name, typeName, elemKind,
isAbstract: declaration.isAbstract,
isDeprecated: _isDeprecated(declaration),
classDecl: declaration.parent,
@@ -368,7 +370,8 @@
@override
void declaredParam(SimpleIdentifier id, TypeName typeName) {
if (optype.includeReturnValueSuggestions) {
- _addLocalSuggestion(id, typeName, protocol.ElementKind.PARAMETER,
+ _addLocalSuggestion_includeReturnValueSuggestions(
+ id, typeName, protocol.ElementKind.PARAMETER,
relevance: DART_RELEVANCE_PARAMETER);
}
}
@@ -377,13 +380,51 @@
void declaredTopLevelVar(
VariableDeclarationList varList, VariableDeclaration varDecl) {
if (optype.includeReturnValueSuggestions) {
- _addLocalSuggestion(
+ _addLocalSuggestion_includeReturnValueSuggestions(
varDecl.name, varList.type, protocol.ElementKind.TOP_LEVEL_VARIABLE,
isDeprecated: _isDeprecated(varList) || _isDeprecated(varDecl),
relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
}
}
+ void _addLocalSuggestion_includeTypeNameSuggestions(
+ SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
+ {bool isAbstract: false,
+ bool isDeprecated: false,
+ ClassDeclaration classDecl,
+ FormalParameterList param,
+ int relevance: DART_RELEVANCE_DEFAULT}) {
+ relevance = optype.typeNameSuggestionsFilter(
+ _staticTypeOfIdentifier(id), relevance);
+ if (relevance != null) {
+ _addLocalSuggestion(id, typeName, elemKind,
+ isAbstract: isAbstract,
+ isDeprecated: isDeprecated,
+ classDecl: classDecl,
+ param: param,
+ relevance: relevance);
+ }
+ }
+
+ void _addLocalSuggestion_includeReturnValueSuggestions(
+ SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
+ {bool isAbstract: false,
+ bool isDeprecated: false,
+ ClassDeclaration classDecl,
+ FormalParameterList param,
+ int relevance: DART_RELEVANCE_DEFAULT}) {
+ relevance = optype.returnValueSuggestionsFilter(
+ _staticTypeOfIdentifier(id), relevance);
+ if (relevance != null) {
+ _addLocalSuggestion(id, typeName, elemKind,
+ isAbstract: isAbstract,
+ isDeprecated: isDeprecated,
+ classDecl: classDecl,
+ param: param,
+ relevance: relevance);
+ }
+ }
+
void _addLocalSuggestion(
SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
{bool isAbstract: false,
@@ -402,14 +443,7 @@
suggestion.completion.startsWith('_')) {
suggestion.relevance = privateMemberRelevance;
}
- // if includeTypeNameSuggestions, then use the filter
- if (optype.includeTypeNameSuggestions) {
- if (optype.typeNameSuggestionsFilter(_staticTypeOfIdentifier(id))) {
- suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
- }
- } else {
- suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
- }
+ suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
suggestion.element = _createLocalElement(request.source, elemKind, id,
isAbstract: isAbstract,
isDeprecated: isDeprecated,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
index 3314403..fdeca37 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
@@ -39,7 +39,7 @@
}
// Resolve the target to determine the type
- await request.resolveExpression(targetId);
+ await request.resolveContainingExpression(targetId);
// Recompute the target since resolution may have changed it
AstNode node = request.target.containingNode;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
index d5f206c..e8cc82d 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
@@ -5,6 +5,7 @@
library services.completion.dart.optype;
import 'package:analysis_server/src/protocol_server.dart' hide Element;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
@@ -14,6 +15,8 @@
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
+typedef int SuggestionsFilter(DartType dartType, int relevance);
+
/**
* An [AstVisitor] for determining whether top level suggestions or invocation
* suggestions should be made based upon the type of node in which the
@@ -26,16 +29,27 @@
bool includeConstructorSuggestions = false;
/**
+ * If [includeConstructorSuggestions] is set to true, then this function may
+ * be set to a non-default function to filter out potential suggestions (null)
+ * based on their static [DartType], or change the relative relevance by
+ * returning a higher or lower relevance.
+ */
+ SuggestionsFilter constructorSuggestionsFilter =
+ (DartType _, int relevance) => relevance;
+
+ /**
* Indicates whether type names should be suggested.
*/
bool includeTypeNameSuggestions = false;
/**
- * If [includeTypeNameSuggestions] is set to true, then this function may be
- * set to the non-default function to filter out potential suggestions based
- * on their static [DartType].
+ * If [includeTypeNameSuggestions] is set to true, then this function may
+ * be set to a non-default function to filter out potential suggestions (null)
+ * based on their static [DartType], or change the relative relevance by
+ * returning a higher or lower relevance.
*/
- Function typeNameSuggestionsFilter = (DartType _) => true;
+ SuggestionsFilter typeNameSuggestionsFilter =
+ (DartType _, int relevance) => relevance;
/**
* Indicates whether setters along with methods and functions that
@@ -50,6 +64,15 @@
bool includeReturnValueSuggestions = false;
/**
+ * If [includeReturnValueSuggestions] is set to true, then this function may
+ * be set to a non-default function to filter out potential suggestions (null)
+ * based on their static [DartType], or change the relative relevance by
+ * returning a higher or lower relevance.
+ */
+ SuggestionsFilter returnValueSuggestionsFilter =
+ (DartType _, int relevance) => relevance;
+
+ /**
* Indicates whether named arguments should be suggested.
*/
bool includeNamedArgumentSuggestions = false;
@@ -65,6 +88,11 @@
bool includeCaseLabelSuggestions = false;
/**
+ * Indicates whether variable names should be suggested.
+ */
+ bool includeVarNameSuggestions = false;
+
+ /**
* Indicates whether the completion location is in the body of a static method.
*/
bool inStaticMethodBody = false;
@@ -99,18 +127,18 @@
/**
* Indicate whether only type names should be suggested
*/
- bool get includeOnlyTypeNameSuggestions =>
- includeTypeNameSuggestions &&
- !includeNamedArgumentSuggestions &&
+ bool get includeOnlyNamedArgumentSuggestions =>
+ includeNamedArgumentSuggestions &&
+ !includeTypeNameSuggestions &&
!includeReturnValueSuggestions &&
!includeVoidReturnSuggestions;
/**
* Indicate whether only type names should be suggested
*/
- bool get includeOnlyNamedArgumentSuggestions =>
- includeNamedArgumentSuggestions &&
- !includeTypeNameSuggestions &&
+ bool get includeOnlyTypeNameSuggestions =>
+ includeTypeNameSuggestions &&
+ !includeNamedArgumentSuggestions &&
!includeReturnValueSuggestions &&
!includeVoidReturnSuggestions;
}
@@ -181,10 +209,14 @@
void visitAsExpression(AsExpression node) {
if (identical(entity, node.type)) {
optype.includeTypeNameSuggestions = true;
- optype.typeNameSuggestionsFilter = (DartType dartType) {
+ optype.typeNameSuggestionsFilter = (DartType dartType, int relevance) {
DartType staticType = node.expression.staticType;
- return staticType.isDynamic ||
- (dartType.isSubtypeOf(staticType) && dartType != staticType);
+ if (staticType.isDynamic ||
+ (dartType.isSubtypeOf(staticType) && dartType != staticType)) {
+ return relevance;
+ } else {
+ return null;
+ }
};
}
}
@@ -353,6 +385,10 @@
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
}
+ if ((token.isSynthetic || token.lexeme == ';') &&
+ node.expression is Identifier) {
+ optype.includeVarNameSuggestions = true;
+ }
}
}
@@ -433,7 +469,7 @@
optype.includeVoidReturnSuggestions = true;
// TODO (danrubel) void return suggestions only belong after
// the 2nd semicolon. Return value suggestions only belong after the
- // e1st or second semicolon.
+ // first or second semicolon.
}
@override
@@ -486,6 +522,29 @@
void visitInstanceCreationExpression(InstanceCreationExpression node) {
if (identical(entity, node.constructorName)) {
optype.includeConstructorSuggestions = true;
+ optype.constructorSuggestionsFilter = (DartType dartType, int relevance) {
+ DartType localTypeAssertion = null;
+ if (node.parent is VariableDeclaration) {
+ VariableDeclaration varDeclaration =
+ node.parent as VariableDeclaration;
+ localTypeAssertion = varDeclaration.element.type;
+ } else if (node.parent is AssignmentExpression) {
+ AssignmentExpression assignmentExpression =
+ node.parent as AssignmentExpression;
+ localTypeAssertion = assignmentExpression.leftHandSide.staticType;
+ }
+ if (localTypeAssertion == null ||
+ dartType == null ||
+ localTypeAssertion.isDynamic) {
+ return relevance;
+ } else if (localTypeAssertion == dartType) {
+ return relevance + DART_RELEVANCE_INCREMENT;
+ } else if (dartType.isSubtypeOf(localTypeAssertion)) {
+ return relevance;
+ } else {
+ return null;
+ }
+ };
}
}
@@ -503,10 +562,14 @@
void visitIsExpression(IsExpression node) {
if (identical(entity, node.type)) {
optype.includeTypeNameSuggestions = true;
- optype.typeNameSuggestionsFilter = (DartType dartType) {
+ optype.typeNameSuggestionsFilter = (DartType dartType, int relevance) {
DartType staticType = node.expression.staticType;
- return staticType.isDynamic ||
- (dartType.isSubtypeOf(staticType) && dartType != staticType);
+ if (staticType.isDynamic ||
+ (dartType.isSubtypeOf(staticType) && dartType != staticType)) {
+ return relevance;
+ } else {
+ return null;
+ }
};
}
}
@@ -548,6 +611,18 @@
void visitNamedExpression(NamedExpression node) {
if (identical(entity, node.expression)) {
optype.includeReturnValueSuggestions = true;
+ optype.returnValueSuggestionsFilter = (DartType dartType, int relevance) {
+ DartType type = node.element?.type;
+ if (type != null &&
+ dartType != null &&
+ !type.isDynamic &&
+ dartType.isSubtypeOf(type)) {
+ // is correct type
+ return relevance + DART_RELEVANCE_INCREMENT;
+ } else {
+ return relevance;
+ }
+ };
optype.includeTypeNameSuggestions = true;
}
}
@@ -732,13 +807,26 @@
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
- if ((node.keyword == null || node.keyword.lexeme != 'var') &&
- (node.type == null || identical(entity, node.type))) {
- optype.includeTypeNameSuggestions = true;
+ if (node.keyword == null || node.keyword.lexeme != 'var') {
+ if (node.type == null || identical(entity, node.type)) {
+ optype.includeTypeNameSuggestions = true;
+ } else if (node.type != null && entity is VariableDeclaration) {
+ optype.includeVarNameSuggestions = true;
+ }
}
}
@override
+ void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ if (entity is Token) {
+ Token token = entity;
+ if (token.isSynthetic || token.lexeme == ';') {
+ optype.includeVarNameSuggestions = true;
+ }
+ }
+ }
+
+ @override
void visitVariableDeclarationStatement(VariableDeclarationStatement node) {}
@override
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
index d950448..0fcb490 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
@@ -7,7 +7,7 @@
import 'dart:async';
import 'package:analysis_server/src/protocol_server.dart'
- show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
+ show CompletionSuggestion, CompletionSuggestionKind;
import 'package:analysis_server/src/protocol_server.dart' as protocol
hide CompletionSuggestion, CompletionSuggestionKind;
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
@@ -15,7 +15,7 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/generated/source.dart';
/**
@@ -39,13 +39,14 @@
// Generate a collection of inherited members
ClassElement classElem = classDecl.element;
InheritanceManager manager = new InheritanceManager(classElem.library);
- MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(classElem);
+ Map<String, ExecutableElement> map =
+ manager.getMembersInheritedFromInterfaces(classElem);
List<String> memberNames = _computeMemberNames(map, classElem);
// Build suggestions
List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
for (String memberName in memberNames) {
- ExecutableElement element = map.get(memberName);
+ ExecutableElement element = map[memberName];
// Gracefully degrade if the overridden element has not been resolved.
if (element.returnType != null) {
CompletionSuggestion suggestion =
@@ -106,11 +107,10 @@
* implemented members of the class represented by the given [element].
* The [map] is used to find all of the members that are inherited.
*/
- List<String> _computeMemberNames(MemberMap map, ClassElement element) {
+ List<String> _computeMemberNames(
+ Map<String, ExecutableElement> map, ClassElement element) {
List<String> memberNames = <String>[];
- int count = map.size;
- for (int i = 0; i < count; i++) {
- String memberName = map.getKey(i);
+ for (String memberName in map.keys) {
if (!_hasMember(element, memberName)) {
memberNames.add(memberName);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
index d7687f9..f280cb3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -12,8 +12,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/visitor.dart';
-import '../../../protocol_server.dart'
- show CompletionSuggestion, CompletionSuggestionKind;
+import '../../../protocol_server.dart' show CompletionSuggestion;
/**
* A contributor for calculating static member invocation / access suggestions
@@ -30,7 +29,7 @@
}
// Resolve the expression and the containing library
- await request.resolveExpression(request.dotTarget);
+ await request.resolveContainingExpression(request.dotTarget);
// Recompute the target since resolution may have changed it
Expression targetId = request.dotTarget;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index cd9dfc0..0cf9318 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -14,8 +14,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import '../../../protocol_server.dart'
- show CompletionSuggestion, CompletionSuggestionKind;
+import '../../../protocol_server.dart' show CompletionSuggestion;
/**
* A contributor for calculating instance invocation / access suggestions
@@ -33,7 +32,7 @@
}
// Resolve the expression and the containing library
- await request.resolveExpression(parsedExpression);
+ await request.resolveContainingExpression(parsedExpression);
LibraryElement containingLibrary = request.libraryElement;
// Gracefully degrade if the library element could not be resolved
// e.g. detached part file or source change
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
new file mode 100644
index 0000000..71ac473
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
@@ -0,0 +1,94 @@
+// 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 services.completion.contributor.dart.variableName;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'
+ show DartCompletionRequestImpl;
+import 'package:analysis_server/src/services/completion/dart/optype.dart';
+import 'package:analysis_server/src/services/correction/name_suggestion.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+
+CompletionSuggestion _createNameSuggestion(String name) {
+ if (name == null || name.isEmpty) {
+ return null;
+ }
+ return new CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
+ DART_RELEVANCE_DEFAULT, name, name.length, 0, false, false);
+}
+
+String _getStringName(Identifier id) {
+ if (id == null) {
+ return null;
+ }
+ if (id is SimpleIdentifier) {
+ return id.name;
+ } else if (id is PrefixedIdentifier) {
+ return id.identifier.name;
+ }
+ return id.name;
+}
+
+/**
+ * A contributor for calculating suggestions for variable names.
+ */
+class VariableNameContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ OpType optype = (request as DartCompletionRequestImpl).opType;
+
+ // Collect suggestions from the specific child [AstNode] that contains
+ // the completion offset and all of its parents recursively.
+ if (optype.includeVarNameSuggestions) {
+ // Resolution not needed for this completion
+
+ AstNode node = request.target.containingNode;
+ String strName = null;
+ if (node is ExpressionStatement) {
+ if (node.expression is Identifier) {
+ strName = _getStringName(node.expression as Identifier);
+ }
+ } else if (node is VariableDeclarationList) {
+ strName = _getStringName(node.type.name);
+ } else if (node is TopLevelVariableDeclaration) {
+ // The parser parses 'Foo ' and 'Foo ;' differently, resulting in the
+ // following.
+ // 'Foo ': handled above
+ // 'Foo ;': TopLevelVariableDeclaration with type null, and a first
+ // variable of 'Foo'
+ VariableDeclarationList varDeclarationList = node.variables;
+ if (varDeclarationList.type != null) {
+ strName = _getStringName(varDeclarationList.type.name);
+ } else {
+ NodeList<VariableDeclaration> varDeclarations =
+ varDeclarationList.variables;
+ if (varDeclarations.length == 1) {
+ VariableDeclaration varDeclaration = varDeclarations.first;
+ strName = _getStringName(varDeclaration.name);
+ }
+ }
+ }
+ if (strName == null) {
+ return EMPTY_LIST;
+ }
+
+ List<String> variableNameSuggestions = getCamelWordCombinations(strName);
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ for (String varName in variableNameSuggestions) {
+ CompletionSuggestion suggestion = _createNameSuggestion(varName);
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+ return suggestions;
+ }
+ return EMPTY_LIST;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index fbbd9a8..244fb3d 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -234,7 +234,7 @@
}
// add edit
Token keyword = declaredIdentifier.keyword;
- if (keyword is KeywordToken && keyword.keyword == Keyword.VAR) {
+ if (keyword.keyword == Keyword.VAR) {
SourceRange range = rangeToken(keyword);
_addReplaceEdit(range, typeSource);
} else {
@@ -338,7 +338,7 @@
}
// add edit
Token keyword = declarationList.keyword;
- if (keyword is KeywordToken && keyword.keyword == Keyword.VAR) {
+ if (keyword.keyword == Keyword.VAR) {
SourceRange range = rangeToken(keyword);
_addReplaceEdit(range, typeSource);
} else {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 6c3a1e6..b1dd15b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1647,7 +1647,6 @@
VariableDeclarationList declarationList = variable.parent;
Token keywordToken = declarationList.keyword;
if (declarationList.variables.length == 1 &&
- keywordToken is KeywordToken &&
keywordToken.keyword == Keyword.FINAL) {
if (declarationList.type != null) {
SourceRange range =
diff --git a/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart b/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart
index c28dae5..12d8c29 100644
--- a/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart
+++ b/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart
@@ -12,6 +12,21 @@
List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
/**
+ * Returns all variants of names by removing leading words one by one.
+ */
+List<String> getCamelWordCombinations(String name) {
+ List<String> result = [];
+ List<String> parts = getCamelWords(name);
+ for (int i = 0; i < parts.length; i++) {
+ var s1 = parts[i].toLowerCase();
+ var s2 = parts.skip(i + 1).join();
+ String suggestion = '$s1$s2';
+ result.add(suggestion);
+ }
+ return result;
+}
+
+/**
* Returns possible names for a variable with the given expected type and
* expression assigned.
*/
@@ -23,12 +38,12 @@
String nameFromExpression = _getBaseNameFromExpression(assignedExpression);
if (nameFromExpression != null) {
nameFromExpression = removeStart(nameFromExpression, '_');
- _addAll(excluded, res, _getCamelWordCombinations(nameFromExpression));
+ _addAll(excluded, res, getCamelWordCombinations(nameFromExpression));
}
String nameFromParent =
_getBaseNameFromLocationInParent(assignedExpression);
if (nameFromParent != null) {
- _addAll(excluded, res, _getCamelWordCombinations(nameFromParent));
+ _addAll(excluded, res, getCamelWordCombinations(nameFromParent));
}
}
// use type
@@ -41,7 +56,7 @@
} else if ('String' == typeName) {
_addSingleCharacterName(excluded, res, 0x73);
} else {
- _addAll(excluded, res, _getCamelWordCombinations(typeName));
+ _addAll(excluded, res, getCamelWordCombinations(typeName));
}
res.remove(typeName);
}
@@ -80,7 +95,7 @@
}
// split camel-case into separate suggested names
Set<String> res = new Set();
- _addAll(excluded, res, _getCamelWordCombinations(text));
+ _addAll(excluded, res, getCamelWordCombinations(text));
return new List.from(res);
}
@@ -200,18 +215,3 @@
// unknown
return null;
}
-
-/**
- * Returns all variants of names by removing leading words one by one.
- */
-List<String> _getCamelWordCombinations(String name) {
- List<String> result = [];
- List<String> parts = getCamelWords(name);
- for (int i = 0; i < parts.length; i++) {
- var s1 = parts[i].toLowerCase();
- var s2 = parts.skip(i + 1).join();
- String suggestion = '$s1$s2';
- result.add(suggestion);
- }
- return result;
-}
diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
index 9a83cb2..b0058aa 100644
--- a/pkg/analysis_server/lib/src/services/correction/namespace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
@@ -6,7 +6,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
/**
* Returns the [Element] exported from the given [LibraryElement].
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 1603ef3..ca38579 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -17,7 +17,6 @@
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
@@ -1413,16 +1412,13 @@
*/
class TokenUtils {
/**
- * @return the first [KeywordToken] with given [Keyword], may be <code>null</code> if
- * not found.
+ * Return the first token in the list of [tokens] representing the given
+ * [keyword], or `null` if there is no such token.
*/
- static KeywordToken findKeywordToken(List<Token> tokens, Keyword keyword) {
+ static Token findKeywordToken(List<Token> tokens, Keyword keyword) {
for (Token token in tokens) {
- if (token is KeywordToken) {
- KeywordToken keywordToken = token;
- if (keywordToken.keyword == keyword) {
- return keywordToken;
- }
+ if (token.keyword == keyword) {
+ return token;
}
}
return null;
diff --git a/pkg/analysis_server/lib/src/single_context_manager.dart b/pkg/analysis_server/lib/src/single_context_manager.dart
new file mode 100644
index 0000000..bdc3a67
--- /dev/null
+++ b/pkg/analysis_server/lib/src/single_context_manager.dart
@@ -0,0 +1,504 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.single_context_manager;
+
+import 'dart:async';
+import 'dart:core' hide Resource;
+import 'dart:math' as math;
+
+import 'package:analysis_server/src/context_manager.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/util/glob.dart';
+import 'package:path/path.dart' as path;
+import 'package:watcher/watcher.dart';
+
+/**
+ * A function that will return a [UriResolver] that can be used to resolve
+ * `package:` URIs in [SingleContextManager].
+ */
+typedef UriResolver PackageResolverProvider();
+
+/**
+ * Implementation of [ContextManager] that supports only one [AnalysisContext].
+ * So, sources from all analysis roots are added to this single context. All
+ * features that could otherwise cause creating additional contexts, such as
+ * presence of `pubspec.yaml` or `.packages` files, or `.analysis_options` files
+ * are ignored.
+ */
+class SingleContextManager implements ContextManager {
+ /**
+ * The [ResourceProvider] using which paths are converted into [Resource]s.
+ */
+ final ResourceProvider resourceProvider;
+
+ /**
+ * The context used to work with file system paths.
+ */
+ path.Context pathContext;
+
+ /**
+ * The manager used to access the SDK that should be associated with a
+ * particular context.
+ */
+ final DartSdkManager sdkManager;
+
+ /**
+ * A function that will return a [UriResolver] that can be used to resolve
+ * `package:` URIs.
+ */
+ final PackageResolverProvider packageResolverProvider;
+
+ /**
+ * A list of the globs used to determine which files should be analyzed.
+ */
+ final List<Glob> analyzedFilesGlobs;
+
+ /**
+ * The list of included paths (folders and files) most recently passed to
+ * [setRoots].
+ */
+ List<String> includedPaths = <String>[];
+
+ /**
+ * The list of excluded paths (folders and files) most recently passed to
+ * [setRoots].
+ */
+ List<String> excludedPaths = <String>[];
+
+ /**
+ * The map of package roots most recently passed to [setRoots].
+ */
+ Map<String, String> packageRoots = <String, String>{};
+
+ /**
+ * Same as [packageRoots], except that source folders have been normalized
+ * and non-folders have been removed.
+ */
+ Map<String, String> normalizedPackageRoots = <String, String>{};
+
+ @override
+ ContextManagerCallbacks callbacks;
+
+ /**
+ * The context in which everything is being analyzed.
+ */
+ AnalysisContext context;
+
+ /**
+ * The folder associated with the context.
+ */
+ Folder contextFolder;
+
+ /**
+ * The current watch subscriptions.
+ */
+ Map<String, StreamSubscription<WatchEvent>> watchSubscriptions =
+ new Map<String, StreamSubscription<WatchEvent>>();
+
+ /**
+ * The [packageResolverProvider] must not be `null`.
+ */
+ SingleContextManager(this.resourceProvider, this.sdkManager,
+ this.packageResolverProvider, this.analyzedFilesGlobs) {
+ pathContext = resourceProvider.pathContext;
+ }
+
+ @override
+ Iterable<AnalysisContext> get analysisContexts =>
+ context == null ? <AnalysisContext>[] : <AnalysisContext>[context];
+
+ @override
+ Map<Folder, AnalysisContext> get folderMap => {contextFolder: context};
+
+ @override
+ List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
+ if (context == null || !includedPaths.contains(analysisRoot.path)) {
+ return <AnalysisContext>[];
+ }
+ return <AnalysisContext>[context];
+ }
+
+ @override
+ AnalysisContext getContextFor(String path) {
+ if (context == null) {
+ return null;
+ } else if (_isContainedIn(includedPaths, path)) {
+ return context;
+ }
+ return null;
+ }
+
+ @override
+ bool isIgnored(String path) {
+ return !_isContainedIn(includedPaths, path) || _isExcludedPath(path);
+ }
+
+ @override
+ bool isInAnalysisRoot(String path) {
+ return _isContainedIn(includedPaths, path) &&
+ !_isContainedIn(excludedPaths, path);
+ }
+
+ @override
+ void refresh(List<Resource> roots) {
+ if (context != null) {
+ callbacks.removeContext(contextFolder, null);
+ context.dispose();
+ context = null;
+ contextFolder = null;
+ _cancelCurrentWatchSubscriptions();
+ setRoots(includedPaths, excludedPaths, packageRoots);
+ }
+ }
+
+ @override
+ void setRoots(List<String> includedPaths, List<String> excludedPaths,
+ Map<String, String> packageRoots) {
+ includedPaths = _nonOverlappingPaths(includedPaths);
+ excludedPaths = _nonOverlappingPaths(excludedPaths);
+ this.packageRoots = packageRoots;
+ _updateNormalizedPackageRoots();
+ // Update context path.
+ {
+ String contextPath = _commonPrefix(includedPaths);
+ Folder contextFolder = resourceProvider.getFolder(contextPath);
+ if (contextFolder != this.contextFolder) {
+ if (context != null) {
+ callbacks.moveContext(this.contextFolder, contextFolder);
+ }
+ this.contextFolder = contextFolder;
+ }
+ }
+ // Start new watchers and cancel old ones.
+ {
+ Map<String, StreamSubscription<WatchEvent>> newSubscriptions =
+ new Map<String, StreamSubscription<WatchEvent>>();
+ for (String includedPath in includedPaths) {
+ Resource resource = resourceProvider.getResource(includedPath);
+ if (resource is Folder) {
+ // Extract the existing subscription or create a new one.
+ StreamSubscription<WatchEvent> subscription =
+ watchSubscriptions.remove(includedPath);
+ if (subscription == null) {
+ subscription = resource.changes.listen(_handleWatchEvent);
+ }
+ // Remember the subscription.
+ newSubscriptions[includedPath] = subscription;
+ }
+ _cancelCurrentWatchSubscriptions();
+ this.watchSubscriptions = newSubscriptions;
+ }
+ }
+ // Create or update the analysis context.
+ if (context == null) {
+ UriResolver packageResolver = packageResolverProvider();
+ context = callbacks.addContext(contextFolder, new AnalysisOptionsImpl(),
+ new CustomPackageResolverDisposition(packageResolver));
+ ChangeSet changeSet =
+ _buildChangeSet(added: _includedFiles(includedPaths, excludedPaths));
+ callbacks.applyChangesToContext(contextFolder, changeSet);
+ } else {
+ // TODO(brianwilkerson) Optimize this.
+ List<File> oldFiles =
+ _includedFiles(this.includedPaths, this.excludedPaths);
+ List<File> newFiles = _includedFiles(includedPaths, excludedPaths);
+ ChangeSet changeSet = _buildChangeSet(
+ added: _diff(newFiles, oldFiles), removed: _diff(oldFiles, newFiles));
+ callbacks.applyChangesToContext(contextFolder, changeSet);
+ }
+ this.includedPaths = includedPaths;
+ this.excludedPaths = excludedPaths;
+ }
+
+ /**
+ * Recursively add the given [resource] (if it's a file) or its children (if
+ * it's a folder) to the [addedFiles].
+ */
+ void _addFilesInResource(
+ List<File> addedFiles, Resource resource, List<String> excludedPaths) {
+ if (_isImplicitlyExcludedResource(resource)) {
+ return;
+ }
+ String path = resource.path;
+ if (_isEqualOrWithinAny(excludedPaths, path)) {
+ return;
+ }
+ if (resource is File) {
+ if (_matchesAnyAnalyzedFilesGlob(path) && resource.exists) {
+ addedFiles.add(resource);
+ }
+ } else if (resource is Folder) {
+ for (Resource child in _getChildrenSafe(resource)) {
+ _addFilesInResource(addedFiles, child, excludedPaths);
+ }
+ }
+ }
+
+ ChangeSet _buildChangeSet({List<File> added, List<File> removed}) {
+ ChangeSet changeSet = new ChangeSet();
+ if (added != null) {
+ for (File file in added) {
+ Source source = createSourceInContext(context, file);
+ changeSet.addedSource(source);
+ }
+ }
+ if (removed != null) {
+ for (File file in removed) {
+ Source source = createSourceInContext(context, file);
+ changeSet.removedSource(source);
+ }
+ }
+ return changeSet;
+ }
+
+ void _cancelCurrentWatchSubscriptions() {
+ for (StreamSubscription<WatchEvent> subscription
+ in watchSubscriptions.values) {
+ subscription.cancel();
+ }
+ watchSubscriptions.clear();
+ }
+
+ String _commonPrefix(List<String> paths) {
+ if (paths.isEmpty) {
+ return '';
+ }
+ List<String> left = pathContext.split(paths[0]);
+ int count = left.length;
+ for (int i = 1; i < paths.length; i++) {
+ List<String> right = pathContext.split(paths[i]);
+ count = _commonComponents(left, count, right);
+ }
+ return pathContext.joinAll(left.sublist(0, count));
+ }
+
+ List<Resource> _existingResources(List<String> pathList) {
+ List<Resource> resources = <Resource>[];
+ for (String path in pathList) {
+ Resource resource = resourceProvider.getResource(path);
+ if (resource is Folder) {
+ resources.add(resource);
+ } else if (!resource.exists) {
+ // Non-existent resources are ignored. TODO(paulberry): we should set
+ // up a watcher to ensure that if the resource appears later, we will
+ // begin analyzing it.
+ } else if (resource is File) {
+ resources.add(resource);
+ } else {
+ throw new UnimplementedError('$path is not a folder. '
+ 'Only support for file and folder analysis is implemented.');
+ }
+ }
+ return resources;
+ }
+
+ void _handleWatchEvent(WatchEvent event) {
+ String path = event.path;
+ // Ignore if excluded.
+ if (_isExcludedPath(path)) {
+ return;
+ }
+ // Ignore if not in a root.
+ if (!_isContainedIn(includedPaths, path)) {
+ return;
+ }
+ // Handle the change.
+ switch (event.type) {
+ case ChangeType.ADD:
+ Resource resource = resourceProvider.getResource(path);
+ if (resource is File) {
+ if (_matchesAnyAnalyzedFilesGlob(path)) {
+ callbacks.applyChangesToContext(
+ contextFolder, _buildChangeSet(added: <File>[resource]));
+ }
+ }
+ break;
+ case ChangeType.REMOVE:
+ List<Source> sources = context.getSourcesWithFullName(path);
+ if (!sources.isEmpty) {
+ ChangeSet changeSet = new ChangeSet();
+ sources.forEach(changeSet.removedSource);
+ callbacks.applyChangesToContext(contextFolder, changeSet);
+ }
+ break;
+ case ChangeType.MODIFY:
+ List<Source> sources = context.getSourcesWithFullName(path);
+ if (!sources.isEmpty) {
+ ChangeSet changeSet = new ChangeSet();
+ sources.forEach(changeSet.changedSource);
+ callbacks.applyChangesToContext(contextFolder, changeSet);
+ }
+ break;
+ }
+ }
+
+ List<File> _includedFiles(
+ List<String> includedPaths, List<String> excludedPaths) {
+ List<Resource> includedResources = _existingResources(includedPaths);
+ List<File> includedFiles = <File>[];
+ for (Resource resource in includedResources) {
+ _addFilesInResource(includedFiles, resource, excludedPaths);
+ }
+ return includedFiles;
+ }
+
+ bool _isContainedIn(List<String> pathList, String path) {
+ for (String pathInList in pathList) {
+ if (_isEqualOrWithin(pathInList, path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _isEqualOrWithin(String parent, String child) {
+ return child == parent || pathContext.isWithin(parent, child);
+ }
+
+ bool _isEqualOrWithinAny(List<String> parents, String child) {
+ for (String parent in parents) {
+ if (_isEqualOrWithin(parent, child)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return `true` if the given [path] should be excluded, using explicit
+ * or implicit rules.
+ */
+ bool _isExcludedPath(String path) {
+ List<String> parts = resourceProvider.pathContext.split(path);
+ // Implicit rules.
+ for (String part in parts) {
+ if (part.startsWith('.')) {
+ return true;
+ }
+ }
+ // Explicitly excluded paths.
+ if (_isEqualOrWithinAny(excludedPaths, path)) {
+ return true;
+ }
+ // OK
+ return false;
+ }
+
+ /**
+ * Return `true` if the given [resource] and children should be excluded
+ * because of some implicit exclusion rules, e.g. `.name`.
+ */
+ bool _isImplicitlyExcludedResource(Resource resource) {
+ String shortName = resource.shortName;
+ if (shortName.startsWith('.')) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return `true` if the given [path] matches one of the [analyzedFilesGlobs].
+ */
+ bool _matchesAnyAnalyzedFilesGlob(String path) {
+ for (Glob glob in analyzedFilesGlobs) {
+ if (glob.matches(path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return a list consisting of the elements from [pathList] that describe the
+ * minimal set of directories that include everything in the original list of
+ * paths and nothing more. In particular:
+ *
+ * * if a path is in the input list multiple times it will appear at most
+ * once in the output list, and
+ * * if a directory D and a subdirectory of it are both in the input list
+ * then only the directory D will be in the output list.
+ *
+ * The original list is not modified.
+ */
+ List<String> _nonOverlappingPaths(List<String> pathList) {
+ List<String> sortedPaths = new List<String>.from(pathList);
+ sortedPaths.sort((a, b) => a.length - b.length);
+ int pathCount = sortedPaths.length;
+ for (int i = pathCount - 1; i > 0; i--) {
+ String path = sortedPaths[i];
+ for (int j = 0; j < i; j++) {
+ if (_isEqualOrWithin(path, sortedPaths[j])) {
+ sortedPaths.removeAt(i);
+ break;
+ }
+ }
+ }
+ return sortedPaths;
+ }
+
+ /**
+ * Normalize all package root sources by mapping them to folders on the
+ * filesystem. Ignore any package root sources that aren't folders.
+ */
+ void _updateNormalizedPackageRoots() {
+ normalizedPackageRoots = <String, String>{};
+ packageRoots.forEach((String sourcePath, String targetPath) {
+ Resource resource = resourceProvider.getResource(sourcePath);
+ if (resource is Folder) {
+ normalizedPackageRoots[resource.path] = targetPath;
+ }
+ });
+ }
+
+ /**
+ * Create and return a source representing the given [file] within the given
+ * [context].
+ */
+ static Source createSourceInContext(AnalysisContext context, File file) {
+ // TODO(brianwilkerson) Optimize this, by allowing support for source
+ // factories to restore URI's from a file path rather than a source.
+ Source source = file.createSource();
+ if (context == null) {
+ return source;
+ }
+ Uri uri = context.sourceFactory.restoreUri(source);
+ return file.createSource(uri);
+ }
+
+ static int _commonComponents(
+ List<String> left, int count, List<String> right) {
+ int max = math.min(count, right.length);
+ for (int i = 0; i < max; i++) {
+ if (left[i] != right[i]) {
+ return i;
+ }
+ }
+ return max;
+ }
+
+ /**
+ * Return a list of all the files in the [left] that are not in the [right].
+ */
+ static List<File> _diff(List<File> left, List<File> right) {
+ List<File> diff = new List.from(left);
+ for (File file in right) {
+ diff.remove(file);
+ }
+ return diff;
+ }
+
+ static List<Resource> _getChildrenSafe(Folder folder) {
+ try {
+ return folder.getChildren();
+ } on FileSystemException {
+ // The folder either doesn't exist or cannot be read.
+ // Either way, there are no children.
+ return const <Resource>[];
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index c3f3fac..1da32a1 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -37,6 +37,7 @@
final ServerPlugin serverPlugin;
final EmbeddedResolverProvider embeddedResolverProvider;
final ResolverProvider packageResolverProvider;
+ final bool useSingleContextManager;
/**
* The analysis server that was created when a client established a
@@ -55,8 +56,9 @@
this.defaultSdk,
this.instrumentationService,
this.serverPlugin,
+ this.embeddedResolverProvider,
this.packageResolverProvider,
- this.embeddedResolverProvider);
+ this.useSingleContextManager);
/**
* Create an analysis server which will communicate with the client using the
@@ -98,8 +100,9 @@
analysisServerOptions,
defaultSdkCreator,
instrumentationService,
- packageResolverProvider: packageResolverProvider,
embeddedResolverProvider: embeddedResolverProvider,
+ packageResolverProvider: packageResolverProvider,
+ useSingleContextManager: useSingleContextManager,
rethrowExceptions: false);
analysisServer.userDefinedPlugins = userDefinedPlugins;
}
diff --git a/pkg/analysis_server/lib/src/watch_manager.dart b/pkg/analysis_server/lib/src/watch_manager.dart
index d4df4d5..04973b9 100644
--- a/pkg/analysis_server/lib/src/watch_manager.dart
+++ b/pkg/analysis_server/lib/src/watch_manager.dart
@@ -176,12 +176,12 @@
/**
* The parent of this node.
*/
- WatchNode parent;
+ WatchNode<T> parent;
/**
* The information for the children of this node.
*/
- final List<WatchNode> _children = <WatchNode>[];
+ final List<WatchNode<T>> _children = <WatchNode<T>>[];
/**
* The tokens that were used to register interest in watching this folder.
@@ -203,7 +203,7 @@
/**
* Return a list containing the children of this node.
*/
- Iterable<WatchNode> get children => _children;
+ Iterable<WatchNode<T>> get children => _children;
/**
* Remove this node from the tree of watched folders.
@@ -220,11 +220,11 @@
* [filePath]. If no other node is found, return this node, even if this node
* does not contain the path.
*/
- WatchNode findParent(String filePath) {
+ WatchNode<T> findParent(String filePath) {
if (_children == null) {
return this;
}
- for (WatchNode childNode in _children) {
+ for (WatchNode<T> childNode in _children) {
if (childNode.folder.isOrContains(filePath)) {
return childNode.findParent(filePath);
}
@@ -237,8 +237,8 @@
* of this node or as a descendent of one of this node's children. Return the
* immediate parent of the newly added node.
*/
- WatchNode insert(WatchNode node) {
- WatchNode parentNode = findParent(node.folder.path);
+ WatchNode<T> insert(WatchNode<T> node) {
+ WatchNode<T> parentNode = findParent(node.folder.path);
parentNode._addChild(node, true);
return parentNode;
}
@@ -256,11 +256,11 @@
* existing children of this node should now be children of the new child, and
* if so, move them.
*/
- void _addChild(WatchNode newChild, bool checkChildren) {
+ void _addChild(WatchNode<T> newChild, bool checkChildren) {
if (checkChildren) {
Folder folder = newChild.folder;
for (int i = _children.length - 1; i >= 0; i--) {
- WatchNode existingChild = _children[i];
+ WatchNode<T> existingChild = _children[i];
if (folder.contains(existingChild.folder.path)) {
newChild._addChild(existingChild, false);
_children.removeAt(i);
@@ -275,10 +275,10 @@
* Remove the given [node] from the list of children of this node. Any
* children of the [node] will become children of this node.
*/
- void _removeChild(WatchNode child) {
+ void _removeChild(WatchNode<T> child) {
_children.remove(child);
- Iterable<WatchNode> grandchildren = child.children;
- for (WatchNode grandchild in grandchildren) {
+ Iterable<WatchNode<T>> grandchildren = child.children;
+ for (WatchNode<T> grandchild in grandchildren) {
grandchild.parent = this;
_children.add(grandchild);
}
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 123cabe..d20e599 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -2373,6 +2373,11 @@
*/
final ResourceProvider resourceProvider;
+ /**
+ * The list of `flushedFiles` in the last [removeContext] invocation.
+ */
+ List<String> lastFlushedFiles;
+
TestContextManagerCallbacks(this.resourceProvider);
/**
@@ -2448,12 +2453,28 @@
}
@override
+ void moveContext(Folder from, Folder to) {
+ String path = from.path;
+ String path2 = to.path;
+ expect(currentContextFilePaths, contains(path));
+ expect(currentContextTimestamps, contains(path));
+ expect(currentContextSources, contains(path));
+ expect(currentContextFilePaths, isNot(contains(path2)));
+ expect(currentContextTimestamps, isNot(contains(path2)));
+ expect(currentContextSources, isNot(contains(path2)));
+ currentContextFilePaths[path2] = currentContextFilePaths.remove(path);
+ currentContextTimestamps[path2] = currentContextTimestamps.remove(path);
+ currentContextSources[path2] = currentContextSources.remove(path);
+ }
+
+ @override
void removeContext(Folder folder, List<String> flushedFiles) {
String path = folder.path;
expect(currentContextPaths, contains(path));
currentContextTimestamps.remove(path);
currentContextFilePaths.remove(path);
currentContextSources.remove(path);
+ lastFlushedFiles = flushedFiles;
}
@override
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index d47638f..4547bcc 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -6,8 +6,6 @@
import 'dart:async';
import 'dart:io';
-@MirrorsUsed(targets: 'mocks', override: '*')
-import 'dart:mirrors';
import 'package:analysis_server/plugin/protocol/protocol.dart'
hide Element, ElementKind;
@@ -283,15 +281,15 @@
* A mock [WebSocket] for testing.
*/
class MockSocket<T> implements WebSocket {
- StreamController controller = new StreamController();
- MockSocket twin;
- Stream stream;
+ StreamController<T> controller = new StreamController<T>();
+ MockSocket<T> twin;
+ Stream<T> stream;
MockSocket();
factory MockSocket.pair() {
- MockSocket socket1 = new MockSocket();
- MockSocket socket2 = new MockSocket();
+ MockSocket<T> socket1 = new MockSocket<T>();
+ MockSocket<T> socket2 = new MockSocket<T>();
socket1.twin = socket2;
socket2.twin = socket1;
socket1.stream = socket2.controller.stream;
@@ -315,7 +313,7 @@
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
- Stream<T> where(bool test(T)) => stream.where(test);
+ Stream<T> where(bool test(T t)) => stream.where(test);
}
class MockSource extends StringTypedMock implements Source {
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 72a57c7..dc011c1 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -369,6 +369,23 @@
return cs;
}
+ CompletionSuggestion assertSuggestName(
+ String name,
+ {int relevance: DART_RELEVANCE_DEFAULT,
+ String importUri,
+ CompletionSuggestionKind kind: CompletionSuggestionKind.IDENTIFIER,
+ bool isDeprecated: false}) {
+ CompletionSuggestion cs = assertSuggest(name,
+ csKind: kind,
+ relevance: relevance,
+ importUri: importUri,
+ isDeprecated: isDeprecated);
+ expect(cs.completion, equals(name));
+ expect(cs.element, isNull);
+ assertHasNoParameterInfo(cs);
+ return cs;
+ }
+
CompletionSuggestion assertSuggestSetter(String name,
{int relevance: DART_RELEVANCE_DEFAULT,
String importUri,
diff --git a/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
index 2f39159..cc4d6f8 100644
--- a/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
@@ -164,4 +164,36 @@
assertNotSuggested('Object');
assertNotSuggested('==');
}
+
+ test_ThisExpression_constructor_param_optional() async {
+ // SimpleIdentifier FieldFormalParameter FormalParameterList
+ addTestSource('''
+ main() { }
+ class Point {
+ int x;
+ int y;
+ Point({this.x, this.^}) {}
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestField('y', 'int', relevance: DART_RELEVANCE_LOCAL_FIELD);
+ assertNotSuggested('x');
+ }
+
+ test_ThisExpression_constructor_param_positional() async {
+ // SimpleIdentifier FieldFormalParameter FormalParameterList
+ addTestSource('''
+ main() { }
+ class Point {
+ int x;
+ int y;
+ Point({this.x, this.^}) {}
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestField('y', 'int', relevance: DART_RELEVANCE_LOCAL_FIELD);
+ assertNotSuggested('x');
+ }
}
diff --git a/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
index 172d767..0d1b13d 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_constructor_contributor_test.dart
@@ -2449,6 +2449,80 @@
assertNotSuggested('Foo');
}
+ test_InstanceCreationExpression_variable_declaration_filter() async {
+ addTestSource('''
+class A {} class B extends A {} class C implements A {} class D {}
+main() {
+ A a = new ^
+}''');
+ await computeSuggestions();
+
+ assertSuggestConstructor('A',
+ elemOffset: -1,
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestConstructor('B',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertSuggestConstructor('C',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertNotSuggested('D');
+ }
+
+ test_InstanceCreationExpression_variable_declaration_filter2() async {
+ addTestSource('''
+class A {} class B extends A {} class C implements A {} class D {}
+main() {
+ A a = new ^;
+}''');
+ await computeSuggestions();
+
+ assertSuggestConstructor('A',
+ elemOffset: -1,
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestConstructor('B',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertSuggestConstructor('C',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertNotSuggested('D');
+ }
+
+ test_InstanceCreationExpression_assignment_expression_filter() async {
+ addTestSource('''
+class A {} class B extends A {} class C implements A {} class D {}
+main() {
+ A a;
+ a = new ^
+}''');
+ await computeSuggestions();
+
+ assertSuggestConstructor('A',
+ elemOffset: -1,
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestConstructor('B',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertSuggestConstructor('C',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertNotSuggested('D');
+ }
+
+ test_InstanceCreationExpression_assignment_expression_filter2() async {
+ addTestSource('''
+class A {} class B extends A {} class C implements A {} class D {}
+main() {
+ A a;
+ a = new ^;
+}''');
+ await computeSuggestions();
+
+ assertSuggestConstructor('A',
+ elemOffset: -1,
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestConstructor('B',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertSuggestConstructor('C',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertNotSuggested('D');
+ }
+
test_InterpolationExpression() async {
// SimpleIdentifier InterpolationExpression StringInterpolation
addSource(
diff --git a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
index eeab8d7..a53e433 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_library_contributor_test.dart
@@ -103,6 +103,114 @@
assertNotSuggested('m');
}
+ test_partFile_InstanceCreationExpression_variable_declaration_filter() async {
+ // ConstructorName InstanceCreationExpression VariableDeclarationList
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addSource(
+ '/testA.dart',
+ '''
+ part of libA;
+ class A {} class B extends A {} class C implements A {} class D {}
+ ''');
+ addTestSource('''
+ library libA;
+ import "/testB.dart";
+ part "/testA.dart";
+ class Local { }
+ main() {
+ A a = new ^
+ }
+ var m;''');
+ await computeLibrariesContaining();
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // A is suggested with a higher relevance
+ assertSuggestConstructor('A',
+ elemOffset: -1,
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestConstructor('B',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertSuggestConstructor('C',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ // D is sorted out
+ assertNotSuggested('D');
+
+ // Suggested by ConstructorContributor
+ assertNotSuggested('Local');
+
+ // Suggested by ImportedReferenceContributor
+ assertNotSuggested('Object');
+ assertNotSuggested('X.c');
+ assertNotSuggested('X._d');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_partFile_InstanceCreationExpression_assignment_filter() async {
+ // ConstructorName InstanceCreationExpression VariableDeclarationList
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addSource(
+ '/testA.dart',
+ '''
+ part of libA;
+ class A {} class B extends A {} class C implements A {} class D {}
+ ''');
+ addTestSource('''
+ library libA;
+ import "/testB.dart";
+ part "/testA.dart";
+ class Local { }
+ main() {
+ A a;
+ // FAIL:
+ a = new ^
+ }
+ var m;''');
+ await computeLibrariesContaining();
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // A is suggested with a higher relevance
+ assertSuggestConstructor('A',
+ elemOffset: -1,
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestConstructor('B',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ assertSuggestConstructor('C',
+ elemOffset: -1, relevance: DART_RELEVANCE_DEFAULT);
+ // D is sorted out
+ assertNotSuggested('D');
+
+ // Suggested by ConstructorContributor
+ assertNotSuggested('Local');
+
+ // Suggested by ImportedReferenceContributor
+ assertNotSuggested('Object');
+ assertNotSuggested('X.c');
+ assertNotSuggested('X._d');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
test_partFile_TypeName() async {
addSource(
'/testB.dart',
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index e617931..a61c9da 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -331,6 +331,45 @@
assertNotSuggested('main');
}
+ test_ArgumentList_namedParam_filter() async {
+ // SimpleIdentifier NamedExpression ArgumentList
+ // InstanceCreationExpression
+ addTestSource('''
+ class A {}
+ class B extends A {}
+ class C implements A {}
+ class D {}
+ class E {
+ A a;
+ E({A someA});
+ }
+ A a = new A();
+ B b = new B();
+ C c = new C();
+ D d = new D();
+ E e = new E(someA: ^);
+ ''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestTopLevelVar('a', 'A',
+ relevance:
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+ assertSuggestTopLevelVar('b', 'B',
+ relevance:
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+ assertSuggestTopLevelVar('c', 'C',
+ relevance:
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+ assertSuggestTopLevelVar('d', 'D',
+ relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
+ assertSuggestTopLevelVar('e', 'E',
+ relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
+ }
+
+
+
test_AsExpression_type() async {
// SimpleIdentifier TypeName AsExpression
addTestSource('''
@@ -362,7 +401,7 @@
assertNotSuggested('Object');
}
- test_IsExpression_type_filter_implements() async {
+ test_AsExpression_type_filter_implements() async {
// SimpleIdentifier TypeName AsExpression
addTestSource('''
class A {} class B implements A {} class C implements A {} class D {}
@@ -378,6 +417,18 @@
assertNotSuggested('Object');
}
+ test_AsExpression_type_filter_undefined_type() async {
+ // SimpleIdentifier TypeName AsExpression
+ addTestSource('''
+class A {}
+f(U u){ (u as ^) }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('A');
+ }
+
test_AssignmentExpression_name() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
@@ -2767,21 +2818,6 @@
assertNotSuggested('Object');
}
- test_IsExpression_type_partial() async {
- // SimpleIdentifier TypeName IsExpression IfStatement
- addTestSource('''
-class A {int x; int y() => 0;}
-main(){var a; if (a is Obj^)}''');
- await computeSuggestions();
-
- expect(replacementOffset, completionOffset - 3);
- expect(replacementLength, 3);
- assertNotSuggested('a');
- assertNotSuggested('main');
- assertSuggestClass('A');
- assertNotSuggested('Object');
- }
-
test_IsExpression_type_filter_extends() async {
// SimpleIdentifier TypeName IsExpression IfStatement
addTestSource('''
@@ -2798,10 +2834,10 @@
assertNotSuggested('Object');
}
- test_IsExpression_type_subtype_implements_filter() async {
+ test_IsExpression_type_filter_implements() async {
// SimpleIdentifier TypeName IsExpression IfStatement
addTestSource('''
-class A {} class B extends A {} class C implements A {} class D {}
+class A {} class B implements A {} class C implements A {} class D {}
f(A a){ if (a is ^) {}}''');
await computeSuggestions();
@@ -2814,6 +2850,33 @@
assertNotSuggested('Object');
}
+ test_IsExpression_type_filter_undefined_type() async {
+ // SimpleIdentifier TypeName AsExpression
+ addTestSource('''
+class A {}
+f(U u){ (u as ^) }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('A');
+ }
+
+ test_IsExpression_type_partial() async {
+ // SimpleIdentifier TypeName IsExpression IfStatement
+ addTestSource('''
+class A {int x; int y() => 0;}
+main(){var a; if (a is Obj^)}''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertSuggestClass('A');
+ assertNotSuggested('Object');
+ }
+
test_keyword() async {
addSource(
'/testB.dart',
@@ -4050,7 +4113,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
- // Contributed by FieldFormalConstructorContributor
+ // Contributed by FieldFormalContributor
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('sb');
@@ -4088,7 +4151,7 @@
expect(replacementOffset, completionOffset - 1);
expect(replacementLength, 1);
- // Contributed by FieldFormalConstructorContributor
+ // Contributed by FieldFormalContributor
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('d');
@@ -4125,7 +4188,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 1);
- // Contributed by FieldFormalConstructorContributor
+ // Contributed by FieldFormalContributor
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('d');
@@ -4163,7 +4226,7 @@
expect(replacementOffset, completionOffset);
expect(replacementLength, 0);
assertNotSuggested('b');
- // Contributed by FieldFormalConstructorContributor
+ // Contributed by FieldFormalContributor
assertNotSuggested('_c');
assertNotSuggested('d');
assertNotSuggested('_e');
diff --git a/pkg/analysis_server/test/services/completion/dart/optype_test.dart b/pkg/analysis_server/test/services/completion/dart/optype_test.dart
index 455495c..f5c89bb 100644
--- a/pkg/analysis_server/test/services/completion/dart/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/optype_test.dart
@@ -54,6 +54,7 @@
bool statementLabel: false,
bool staticMethodBody: false,
bool typeNames: false,
+ bool varNames: false,
bool voidReturn: false,
CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION}) {
expect(visitor.includeCaseLabelSuggestions, caseLabel, reason: 'caseLabel');
@@ -66,6 +67,7 @@
expect(visitor.includeStatementLabelSuggestions, statementLabel,
reason: 'statementLabel');
expect(visitor.includeTypeNameSuggestions, typeNames, reason: 'typeNames');
+ expect(visitor.includeVarNameSuggestions, varNames, reason: 'varNames');
expect(visitor.includeVoidReturnSuggestions, voidReturn,
reason: 'voidReturn');
expect(visitor.inStaticMethodBody, staticMethodBody,
@@ -149,7 +151,7 @@
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('class A {} main() {int a; int ^b = 1;}');
- assertOpType();
+ assertOpType(varNames: true);
}
test_AssignmentExpression_RHS() {
@@ -544,7 +546,25 @@
test_ExpressionStatement_name() {
// ExpressionStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class C {a() {C ^}}');
- assertOpType();
+ assertOpType(varNames: true);
+ }
+
+ test_ExpressionStatement_name_semicolon() {
+ // ExpressionStatement Block BlockFunctionBody MethodDeclaration
+ addTestSource('class C {a() {C ^;}}');
+ assertOpType(varNames: true);
+ }
+
+ test_ExpressionStatement_prefixed_name() {
+ // ExpressionStatement Block BlockFunctionBody MethodDeclaration
+ addTestSource('class C {a() {x.Y ^}}');
+ assertOpType(varNames: true);
+ }
+
+ test_ExpressionStatement_prefixed_name_semicolon() {
+ // ExpressionStatement Block BlockFunctionBody MethodDeclaration
+ addTestSource('class C {a() {x.Y ^;}}');
+ assertOpType(varNames: true);
}
test_ExtendsClause() {
@@ -557,7 +577,7 @@
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// FieldDeclaration
addTestSource('class C {A ^}');
- assertOpType();
+ assertOpType(varNames: true);
}
test_FieldDeclaration_name_var() {
@@ -1407,8 +1427,19 @@
test_TopLevelVariableDeclaration_typed_name() {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// TopLevelVariableDeclaration
+ // _OpTypeAstVisitor.visitVariableDeclarationList is executed with this
+ // source, but _OpTypeAstVisitor.visitTopLevelVariableDeclaration is called
+ // for test_TopLevelVariableDeclaration_typed_name_semicolon
addTestSource('class A {} B ^');
- assertOpType();
+ assertOpType(varNames: true);
+ }
+
+ test_TopLevelVariableDeclaration_typed_name_semicolon() {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // TopLevelVariableDeclaration
+ // See comment in test_TopLevelVariableDeclaration_typed_name
+ addTestSource('class A {} B ^;');
+ assertOpType(varNames: true);
}
test_TopLevelVariableDeclaration_untyped_name() {
@@ -1453,14 +1484,14 @@
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('main() {List<int> m^}');
- assertOpType();
+ assertOpType(varNames: true);
}
test_VariableDeclaration_name_hasSome_simpleType() {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('main() {String m^}');
- assertOpType();
+ assertOpType(varNames: true);
}
test_VariableDeclarationList_final() {
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
index 1d395ac..e9fb6c5 100644
--- a/pkg/analysis_server/test/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -28,6 +28,7 @@
import 'static_member_contributor_test.dart' as static_contributor_test;
import 'type_member_contributor_test.dart' as type_member_contributor_test;
import 'uri_contributor_test.dart' as uri_contributor_test;
+import 'variable_name_contributor_test.dart' as variable_name_contributor_test;
/// Utility for manually running all tests.
main() {
@@ -54,5 +55,6 @@
static_contributor_test.main();
type_member_contributor_test.main();
uri_contributor_test.main();
+ variable_name_contributor_test.main();
});
}
diff --git a/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart
new file mode 100644
index 0000000..72a4cab
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/variable_name_contributor_test.dart
@@ -0,0 +1,199 @@
+// 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.services.completion.variableName;
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/variable_name_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(VariableNameContributorTest);
+}
+
+@reflectiveTest
+class VariableNameContributorTest extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new VariableNameContributor();
+ }
+
+ test_ExpressionStatement_short() async {
+ addTestSource('''
+ f() { A ^ }
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('a');
+ }
+
+ test_ExpressionStatement_short_semicolon() async {
+ addTestSource('''
+ f() { A ^; }
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('a');
+ }
+
+ test_ExpressionStatement_long() async {
+ addTestSource('''
+ f() { AbstractCrazyNonsenseClassName ^ }
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_long_semicolon() async {
+ addTestSource('''
+ f() { AbstractCrazyNonsenseClassName ^; }
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_prefixed() async {
+ addTestSource('''
+ f() { prefix.AbstractCrazyNonsenseClassName ^ }
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_prefixed_semicolon() async {
+ addTestSource('''
+ f() { prefix.AbstractCrazyNonsenseClassName ^; }
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_top_level_short() async {
+ addTestSource('''
+ A ^
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('a');
+ }
+
+ test_ExpressionStatement_top_level_short_semicolon() async {
+ addTestSource('''
+ A ^;
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('a');
+ }
+
+ test_ExpressionStatement_top_level_long() async {
+ addTestSource('''
+ AbstractCrazyNonsenseClassName ^
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_top_level_long_semicolon() async {
+ addTestSource('''
+ AbstractCrazyNonsenseClassName ^;
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_top_level_prefixed() async {
+ addTestSource('''
+ prefix.AbstractCrazyNonsenseClassName ^
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_ExpressionStatement_top_level_prefixed_semicolon() async {
+ addTestSource('''
+ prefix.AbstractCrazyNonsenseClassName ^;
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestName('abstractCrazyNonsenseClassName');
+ assertSuggestName('crazyNonsenseClassName');
+ assertSuggestName('nonsenseClassName');
+ assertSuggestName('className');
+ assertSuggestName('name');
+ }
+
+ test_VariableDeclaration_short() async {
+ addTestSource('''
+ AAA a^
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset-1);
+ expect(replacementLength, 1);
+ assertSuggestName('aaa');
+ }
+
+ test_VariableDeclaration_short_semicolon() async {
+ addTestSource('''
+ AAA a^;
+ ''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset-1);
+ expect(replacementLength, 1);
+ assertSuggestName('aaa');
+ }
+
+}
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 78a5cd4..3715ced 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -496,6 +496,44 @@
''');
}
+ test_createChange_FunctionElement_imported() async {
+ indexUnit(
+ '/foo.dart',
+ r'''
+test() {}
+foo() {}
+''');
+ indexTestUnit('''
+import 'foo.dart';
+main() {
+ print(test);
+ print(test());
+ foo();
+}
+''');
+ // configure refactoring
+ createRenameRefactoringAtString('test);');
+ expect(refactoring.refactoringName, 'Rename Top-Level Function');
+ expect(refactoring.elementKindName, 'function');
+ expect(refactoring.oldName, 'test');
+ refactoring.newName = 'newName';
+ // validate change
+ await assertSuccessfulRefactoring('''
+import 'foo.dart';
+main() {
+ print(newName);
+ print(newName());
+ foo();
+}
+''');
+ assertFileChangeResult(
+ '/foo.dart',
+ '''
+newName() {}
+foo() {}
+''');
+ }
+
test_createChange_PropertyAccessorElement_getter_declaration() {
return _test_createChange_PropertyAccessorElement("test {}");
}
diff --git a/pkg/analysis_server/test/single_context_manager_test.dart b/pkg/analysis_server/test/single_context_manager_test.dart
new file mode 100644
index 0000000..f436006
--- /dev/null
+++ b/pkg/analysis_server/test/single_context_manager_test.dart
@@ -0,0 +1,539 @@
+// Copyright (c) 2016, 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_server.src.single_context_manager;
+
+import 'dart:core' hide Resource;
+
+import 'package:analysis_server/src/single_context_manager.dart';
+import 'package:analyzer/file_system/memory_file_system.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/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/util/glob.dart';
+import 'package:linter/src/plugin/linter_plugin.dart';
+import 'package:path/path.dart';
+import 'package:plugin/manager.dart';
+import 'package:plugin/plugin.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import 'context_manager_test.dart' show TestContextManagerCallbacks;
+import 'mock_sdk.dart';
+import 'mocks.dart';
+import 'utils.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(SingleContextManagerTest);
+}
+
+@reflectiveTest
+class SingleContextManagerTest {
+ MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+
+ TestUriResolver packageResolver;
+ TestContextManagerCallbacks callbacks;
+ SingleContextManager manager;
+
+ List<Glob> get analysisFilesGlobs {
+ List<String> patterns = <String>[
+ '**/*.${AnalysisEngine.SUFFIX_DART}',
+ '**/*.${AnalysisEngine.SUFFIX_HTML}',
+ ];
+ return patterns
+ .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
+ .toList();
+ }
+
+ String newFile(List<String> pathComponents, [String content = '']) {
+ String filePath = posix.joinAll(pathComponents);
+ resourceProvider.newFile(filePath, content);
+ return filePath;
+ }
+
+ String newFolder(List<String> pathComponents) {
+ String folderPath = posix.joinAll(pathComponents);
+ resourceProvider.newFolder(folderPath);
+ return folderPath;
+ }
+
+ void setUp() {
+ packageResolver = new TestUriResolver();
+
+ _processRequiredPlugins();
+ DartSdkManager sdkManager = new DartSdkManager((_) {
+ return new MockSdk();
+ });
+ manager = new SingleContextManager(resourceProvider, sdkManager,
+ () => packageResolver, analysisFilesGlobs);
+ callbacks = new TestContextManagerCallbacks(resourceProvider);
+ manager.callbacks = callbacks;
+ }
+
+ void test_isIgnored_false() {
+ String project = '/project';
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ expect(manager.isIgnored('$project/file.dart'), isFalse);
+ }
+
+ void test_isIgnored_true_inDotFolder() {
+ String project = '/project';
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ expect(manager.isIgnored('$project/foo/.bar/file.dart'), isTrue);
+ }
+
+ void test_isIgnored_true_inExcludedPath() {
+ String project = '/project';
+ String excludedPath = '/project/excluded';
+ manager.setRoots(
+ <String>[project], <String>[excludedPath], <String, String>{});
+ expect(manager.isIgnored('$excludedPath/file.dart'), isTrue);
+ }
+
+ void test_isIgnored_true_notInRoot() {
+ String root1 = '/context/root1';
+ String root2 = '/context/root2';
+ manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
+ expect(manager.isIgnored('$context/root3/file.dart'), isTrue);
+ }
+
+ void test_isInAnalysisRoot_false_inExcludedPath() {
+ String project = '/project';
+ String excludedPath = '/project/excluded';
+ manager.setRoots(
+ <String>[project], <String>[excludedPath], <String, String>{});
+ expect(manager.isInAnalysisRoot('$excludedPath/file.dart'), isFalse);
+ }
+
+ void test_isInAnalysisRoot_false_notInRoot() {
+ String root1 = '/context/root1';
+ String root2 = '/context/root2';
+ manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
+ expect(manager.isInAnalysisRoot('$context/root3/file.dart'), isFalse);
+ }
+
+ void test_isInAnalysisRoot_true() {
+ String project = '/project';
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ expect(manager.isInAnalysisRoot('$project/file.dart'), isTrue);
+ }
+
+ void test_refresh() {
+ String project = '/project';
+ String file1 = '$project/file1.dart';
+ String file2 = '$project/file2.dart';
+ // create files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // set roots
+ manager.setRoots(<String>[project], <String>[file2], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
+ // refresh
+ manager.refresh([]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
+ }
+
+ void test_setRoots_addFolderWithDartFile() {
+ String project = '/project';
+ String file = '$project/lib/foo.dart';
+ resourceProvider.newFile(file, '');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // verify
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file]);
+ }
+
+ void test_setRoots_addFolderWithDartFileInSubfolder() {
+ String project = '/project';
+ String file = '$project/foo/bar.dart';
+ resourceProvider.newFile(file, '');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // verify
+ callbacks.assertContextFiles(project, [file]);
+ }
+
+ void test_setRoots_addFolderWithDummyLink() {
+ String project = '/project';
+ String file = '$project/foo.dart';
+ resourceProvider.newDummyLink(file);
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // verify
+ callbacks.assertContextFiles(project, []);
+ }
+
+ void test_setRoots_exclude_newRoot_withExcludedFile() {
+ String project = '/project';
+ String file1 = '$project/file1.dart';
+ String file2 = '$project/file2.dart';
+ // create files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // set roots
+ manager.setRoots(<String>[project], <String>[file1], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file2]);
+ }
+
+ void test_setRoots_exclude_newRoot_withExcludedFolder() {
+ String project = '/project';
+ String folderA = '$project/aaa';
+ String folderB = '$project/bbb';
+ String fileA = '$folderA/a.dart';
+ String fileB = '$folderB/b.dart';
+ // create files
+ resourceProvider.newFile(fileA, '');
+ resourceProvider.newFile(fileB, '');
+ // set roots
+ manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ }
+
+ void test_setRoots_exclude_sameRoot_addExcludedFile() {
+ String project = '/project';
+ String file1 = '$project/file1.dart';
+ String file2 = '$project/file2.dart';
+ // create files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // set roots
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1, file2]);
+ // exclude "2"
+ manager.setRoots(<String>[project], <String>[file2], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
+ }
+
+ void test_setRoots_exclude_sameRoot_addExcludedFolder() {
+ String project = '/project';
+ String folderA = '$project/aaa';
+ String folderB = '$project/bbb';
+ String fileA = '$folderA/a.dart';
+ String fileB = '$folderB/b.dart';
+ // create files
+ resourceProvider.newFile(fileA, 'library a;');
+ resourceProvider.newFile(fileB, 'library b;');
+ // initially both "aaa/a" and "bbb/b" are included
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA, fileB]);
+ // exclude "bbb/"
+ manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ }
+
+ void test_setRoots_exclude_sameRoot_removeExcludedFile() {
+ String project = '/project';
+ String file1 = '$project/file1.dart';
+ String file2 = '$project/file2.dart';
+ // create files
+ resourceProvider.newFile(file1, '// 1');
+ resourceProvider.newFile(file2, '// 2');
+ // set roots
+ manager.setRoots(<String>[project], <String>[file2], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
+ // stop excluding "2"
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1, file2]);
+ }
+
+ void test_setRoots_exclude_sameRoot_removeExcludedFile_inFolder() {
+ String project = '/project';
+ String file1 = '$project/bin/file1.dart';
+ String file2 = '$project/bin/file2.dart';
+ // create files
+ resourceProvider.newFile(file1, '// 1');
+ resourceProvider.newFile(file2, '// 2');
+ // set roots
+ manager.setRoots(<String>[project], <String>[file2], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
+ // stop excluding "2"
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1, file2]);
+ }
+
+ void test_setRoots_exclude_sameRoot_removeExcludedFolder() {
+ String project = '/project';
+ String folderA = '$project/aaa';
+ String folderB = '$project/bbb';
+ String fileA = '$folderA/a.dart';
+ String fileB = '$folderB/b.dart';
+ // create files
+ resourceProvider.newFile(fileA, 'library a;');
+ resourceProvider.newFile(fileB, 'library b;');
+ // exclude "bbb/"
+ manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ // stop excluding "bbb/"
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA, fileB]);
+ }
+
+ void test_setRoots_ignoreGlobs() {
+ String project = '/project';
+ String file1 = '$project/file.dart';
+ String file2 = '$project/file.foo';
+ // create files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // set roots
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
+ }
+
+ void test_setRoots_newContextFolder_coverNewRoot() {
+ String contextPath = '/context';
+ String root1 = '$contextPath/root1';
+ String file1 = '$root1/file1.dart';
+ String root2 = '$contextPath/root2';
+ String file2 = '$root2/file1.dart';
+ // create files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // cover single root '/context/root1'
+ manager.setRoots(<String>[root1], <String>[], <String, String>{});
+ callbacks.assertContextPaths([root1]);
+ callbacks.assertContextFiles(root1, [file1]);
+ // cover two roots
+ manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
+ callbacks.assertContextPaths([contextPath]);
+ callbacks.assertContextFiles(contextPath, [file1, file2]);
+ // cover single root '/context/root2'
+ manager.setRoots(<String>[root2], <String>[], <String, String>{});
+ callbacks.assertContextPaths([root2]);
+ callbacks.assertContextFiles(root2, [file2]);
+ }
+
+ void test_setRoots_newContextFolder_replace() {
+ String contextPath1 = '/context1';
+ String root11 = '$contextPath1/root1';
+ String root12 = '$contextPath1/root2';
+ String file11 = '$root11/file1.dart';
+ String file12 = '$root12/file2.dart';
+ String contextPath2 = '/context2';
+ String root21 = '$contextPath2/root1';
+ String root22 = '$contextPath2/root2';
+ String file21 = '$root21/file1.dart';
+ String file22 = '$root22/file2.dart';
+ // create files
+ resourceProvider.newFile(file11, '');
+ resourceProvider.newFile(file12, '');
+ resourceProvider.newFile(file21, '');
+ resourceProvider.newFile(file22, '');
+ // set roots in '/context1'
+ manager.setRoots(<String>[root11, root12], <String>[], <String, String>{});
+ callbacks.assertContextPaths([contextPath1]);
+ callbacks.assertContextFiles(contextPath1, [file11, file12]);
+ // set roots in '/context2'
+ manager.setRoots(<String>[root21, root22], <String>[], <String, String>{});
+ callbacks.assertContextPaths([contextPath2]);
+ callbacks.assertContextFiles(contextPath2, [file21, file22]);
+ }
+
+ void test_setRoots_pathContainsDotFile() {
+ // If the path to a file (relative to the context root) contains a folder
+ // whose name begins with '.', then the file is ignored.
+ String project = '/project';
+ String fileA = '$project/foo.dart';
+ String fileB = '$project/.pub/bar.dart';
+ resourceProvider.newFile(fileA, '');
+ resourceProvider.newFile(fileB, '');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ }
+
+ void test_setRoots_rootPathContainsDotFile() {
+ // If the path to the context root itself contains a folder whose name
+ // begins with '.', then that is not sufficient to cause any files in the
+ // context to be ignored.
+ String project = '/.pub/project';
+ String fileA = '$project/foo.dart';
+ resourceProvider.newFile(fileA, '');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ }
+
+ test_watch_addFile() async {
+ String project = '/project';
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // empty folder initially
+ callbacks.assertContextFiles(project, []);
+ // add file
+ String file = '$project/foo.dart';
+ resourceProvider.newFile(file, 'contents');
+ // the file was added
+ await pumpEventQueue();
+ callbacks.assertContextFiles(project, [file]);
+ }
+
+ test_watch_addFile_afterChangingRoots() async {
+ String contextPath = '/context';
+ String root1 = '$contextPath/root1';
+ String root2 = '$contextPath/root2';
+ String file1 = '$root1/file1.dart';
+ String file2 = '$root2/file2.dart';
+ manager.setRoots(<String>[root1], <String>[], <String, String>{});
+ manager.setRoots(<String>[root2], <String>[], <String, String>{});
+ manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
+ manager.setRoots(<String>[root2], <String>[], <String, String>{});
+ // empty folder initially
+ callbacks.assertContextFiles(root2, []);
+ // add files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // the file was added
+ await pumpEventQueue();
+ callbacks.assertContextFiles(root2, [file2]);
+ }
+
+ test_watch_addFile_excluded() async {
+ String project = '/project';
+ String folderA = '$project/aaa';
+ String folderB = '$project/bbb';
+ String fileA = '$folderA/a.dart';
+ String fileB = '$folderB/b.dart';
+ // create files
+ resourceProvider.newFile(fileA, 'library a;');
+ // set roots
+ manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ // add a file, ignored as excluded
+ resourceProvider.newFile(fileB, 'library b;');
+ await pumpEventQueue();
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ }
+
+ test_watch_addFile_notInRoot() async {
+ String contextPath = '/roots';
+ String root1 = '$contextPath/root1';
+ String root2 = '$contextPath/root2';
+ String root3 = '$contextPath/root3';
+ String file1 = '$root1/file1.dart';
+ String file2 = '$root2/file2.dart';
+ String file3 = '$root3/file3.dart';
+ // create files
+ resourceProvider.newFile(file1, '');
+ resourceProvider.newFile(file2, '');
+ // set roots
+ manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
+ callbacks.assertContextPaths([contextPath]);
+ callbacks.assertContextFiles(contextPath, [file1, file2]);
+ // add a file, not in a root - ignored
+ resourceProvider.newFile(file3, '');
+ await pumpEventQueue();
+ callbacks.assertContextPaths([contextPath]);
+ callbacks.assertContextFiles(contextPath, [file1, file2]);
+ }
+
+ test_watch_addFile_pathContainsDotFile() async {
+ // If a file is added and the absolute path to it contains a folder whose
+ // name begins with '.', then the file is ignored.
+ String project = '/project';
+ String fileA = '$project/foo.dart';
+ String fileB = '$project/.pub/bar.dart';
+ resourceProvider.newFile(fileA, '');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ resourceProvider.newFile(fileB, '');
+ await pumpEventQueue();
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
+ }
+
+ test_watch_addFileInSubfolder() async {
+ String project = '/project';
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // empty folder initially
+ callbacks.assertContextFiles(project, []);
+ // add file in subfolder
+ String file = '$project/foo/bar.dart';
+ resourceProvider.newFile(file, 'contents');
+ // the file was added
+ await pumpEventQueue();
+ callbacks.assertContextFiles(project, [file]);
+ }
+
+ test_watch_deleteFile() async {
+ String project = '/project';
+ String file = '$project/foo.dart';
+ // add root with a file
+ resourceProvider.newFile(file, 'contents');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // the file was added
+ callbacks.assertContextFiles(project, [file]);
+ // delete the file
+ resourceProvider.deleteFile(file);
+ await pumpEventQueue();
+ callbacks.assertContextFiles(project, []);
+ }
+
+ test_watch_deleteFolder() async {
+ String project = '/project';
+ String file = '$project/foo.dart';
+ // add root with a file
+ resourceProvider.newFile(file, 'contents');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // the file was added
+ callbacks.assertContextFiles(project, [file]);
+ // delete the folder
+ resourceProvider.deleteFolder(project);
+ await pumpEventQueue();
+ callbacks.assertContextFiles(project, []);
+ }
+
+ test_watch_modifyFile() async {
+ String project = '/project';
+ String file = '$project/foo.dart';
+ // add root with a file
+ resourceProvider.newFile(file, 'contents');
+ manager.setRoots(<String>[project], <String>[], <String, String>{});
+ // the file was added
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[project];
+ expect(filePaths, hasLength(1));
+ expect(filePaths, contains(file));
+ expect(filePaths[file], equals(callbacks.now));
+ // update the file
+ callbacks.now++;
+ resourceProvider.modifyFile(file, 'new contents');
+ await pumpEventQueue();
+ return expect(filePaths[file], equals(callbacks.now));
+ }
+
+ void _processRequiredPlugins() {
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.commandLinePlugin);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
+ plugins.add(linterPlugin);
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
+ }
+}
+
+class TestUriResolver extends UriResolver {
+ @override
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ return null;
+ }
+}
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 395072a..4ff5ea7 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -121,7 +121,8 @@
InstrumentationService.NULL_SERVICE,
serverPlugin,
null,
- null);
+ null,
+ false);
}
}
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index 994f5ef..e830864 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -22,6 +22,7 @@
import 'search/test_all.dart' as search_all;
import 'server_options_test.dart' as server_options;
import 'services/test_all.dart' as services_all;
+import 'single_context_manager_test.dart' as single_context_manager_test;
import 'socket_server_test.dart' as socket_server_test;
import 'source/test_all.dart' as source_all;
import 'src/test_all.dart' as src_all;
@@ -51,6 +52,7 @@
search_all.main();
server_options.main();
services_all.main();
+ single_context_manager_test.main();
socket_server_test.main();
source_all.main();
src_all.main();
diff --git a/pkg/analyzer/doc/tasks.html b/pkg/analyzer/doc/tasks.html
index 2224724..5e242a5 100644
--- a/pkg/analyzer/doc/tasks.html
+++ b/pkg/analyzer/doc/tasks.html
@@ -177,7 +177,10 @@
LINTS [shape=box]
LibraryErrorsReadyTask -> LIBRARY_ERRORS_READY
LibraryUnitErrorsTask -> LIBRARY_UNIT_ERRORS
+ MODIFICATION_TIME -> BuildDirectiveElementsTask
MODIFICATION_TIME -> ParseDartTask
+ MODIFICATION_TIME -> ScanDartTask
+ MODIFICATION_TIME -> VerifyUnitTask
MODIFICATION_TIME [shape=box]
PARSED_UNIT -> BuildCompilationUnitElementTask
PARSED_UNIT -> DartErrorsTask
@@ -198,6 +201,7 @@
ParseDartTask -> LIBRARY_SPECIFIC_UNITS
ParseDartTask -> PARSED_UNIT
ParseDartTask -> PARSE_ERRORS
+ ParseDartTask -> REFERENCED_SOURCES
ParseDartTask -> SOURCE_KIND
ParseDartTask -> UNITS
PartiallyResolveUnitReferencesTask -> CREATED_RESOLVED_UNIT6
@@ -222,6 +226,9 @@
READY_RESOLVED_UNIT -> VerifyUnitTask
READY_RESOLVED_UNIT [shape=box]
REFERENCED_NAMES [shape=box]
+ REFERENCED_SOURCES -> BuildDirectiveElementsTask
+ REFERENCED_SOURCES -> VerifyUnitTask
+ REFERENCED_SOURCES [shape=box]
RESOLVED_UNIT -> GenerateHintsTask
RESOLVED_UNIT -> GenerateLintsTask
RESOLVED_UNIT -> ReadyResolvedUnitTask
diff --git a/pkg/analyzer/lib/dart/ast/token.dart b/pkg/analyzer/lib/dart/ast/token.dart
index 6560a8e..77226be 100644
--- a/pkg/analyzer/lib/dart/ast/token.dart
+++ b/pkg/analyzer/lib/dart/ast/token.dart
@@ -250,6 +250,11 @@
bool get isUserDefinableOperator;
/**
+ * Return the keyword, if a keyword token, or `null` otherwise.
+ */
+ Keyword get keyword;
+
+ /**
* Return the number of characters in the node's source range.
*/
int get length;
diff --git a/pkg/analyzer/lib/instrumentation/instrumentation.dart b/pkg/analyzer/lib/instrumentation/instrumentation.dart
index fe58cdb..92638f7 100644
--- a/pkg/analyzer/lib/instrumentation/instrumentation.dart
+++ b/pkg/analyzer/lib/instrumentation/instrumentation.dart
@@ -106,10 +106,8 @@
*/
void logAnalysisTask(String context, AnalysisTask task) {
if (_instrumentationServer != null) {
- String description =
- (task is AnalysisTask) ? task.description : task.toString();
_instrumentationServer
- .log(_join([TAG_ANALYSIS_TASK, context, description]));
+ .log(_join([TAG_ANALYSIS_TASK, context, task.description]));
}
}
diff --git a/pkg/analyzer/lib/plugin/resolver_provider.dart b/pkg/analyzer/lib/plugin/resolver_provider.dart
index 1172372..ed0e366 100644
--- a/pkg/analyzer/lib/plugin/resolver_provider.dart
+++ b/pkg/analyzer/lib/plugin/resolver_provider.dart
@@ -9,6 +9,10 @@
/**
* A function that will return a [UriResolver] that can be used to resolve a
- * specific kind of URI within the analysis context rooted at the given folder.
+ * specific kind of URI within the analysis context rooted at the given
+ * [folder].
+ *
+ * The given [folder] may be `null` if analysis is performed in an environment
+ * where URI resolution is always the same in any folder.
*/
typedef UriResolver ResolverProvider(Folder folder);
diff --git a/pkg/analyzer/lib/source/analysis_options_provider.dart b/pkg/analyzer/lib/source/analysis_options_provider.dart
index 3e15c64..600dffc 100644
--- a/pkg/analyzer/lib/source/analysis_options_provider.dart
+++ b/pkg/analyzer/lib/source/analysis_options_provider.dart
@@ -38,19 +38,21 @@
/// Provide the options found in [optionsSource].
/// Return an empty options map if the source is null.
Map<String, YamlNode> getOptionsFromString(String optionsSource) {
- var options = <String, YamlNode>{};
+ Map<String, YamlNode> options = <String, YamlNode>{};
if (optionsSource == null) {
return options;
}
- YamlNode doc;
- try {
- doc = loadYamlNode(optionsSource);
- } on YamlException catch (e) {
- throw new OptionsFormatException(e.message, e.span);
- } catch (e) {
- throw new OptionsFormatException('Unable to parse YAML document.');
+ YamlNode safelyLoadYamlNode() {
+ try {
+ return loadYamlNode(optionsSource);
+ } on YamlException catch (e) {
+ throw new OptionsFormatException(e.message, e.span);
+ } catch (e) {
+ throw new OptionsFormatException('Unable to parse YAML document.');
+ }
}
+ YamlNode doc = safelyLoadYamlNode();
// Empty options.
if (doc is YamlScalar && doc.value == null) {
@@ -62,7 +64,7 @@
doc.span);
}
if (doc is YamlMap) {
- (doc as YamlMap).nodes.forEach((k, v) {
+ doc.nodes.forEach((k, YamlNode v) {
var key;
if (k is YamlScalar) {
key = k.value;
diff --git a/pkg/analyzer/lib/source/embedder.dart b/pkg/analyzer/lib/source/embedder.dart
index b55f5d9..78ba661 100644
--- a/pkg/analyzer/lib/source/embedder.dart
+++ b/pkg/analyzer/lib/source/embedder.dart
@@ -211,11 +211,9 @@
if (embedded_libs == null) {
return;
}
- if (embedded_libs is! YamlMap) {
- return;
+ if (embedded_libs is YamlMap) {
+ embedded_libs.forEach((k, v) => _processEmbeddedLibs(k, v, libDir));
}
- (embedded_libs as YamlMap)
- .forEach((k, v) => _processEmbeddedLibs(k, v, libDir));
}
}
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index 8be0a41..7e6e0a0 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -315,9 +315,7 @@
new HashMap<ResultDescriptor, ResultData>();
CacheEntry(this.target) {
- if (target is ElementImpl) {
- (target as ElementImpl).setModifier(Modifier.CACHE_KEY, true);
- }
+ _markAsCacheKey(target);
}
/**
@@ -361,8 +359,9 @@
}
});
_resultMap.clear();
- if (target is ElementImpl) {
- (target as ElementImpl).setModifier(Modifier.CACHE_KEY, false);
+ AnalysisTarget oldTarget = target;
+ if (oldTarget is ElementImpl) {
+ oldTarget.setModifier(Modifier.CACHE_KEY, false);
}
}
@@ -632,6 +631,15 @@
}
/**
+ * If the given `target` is an element, mark it as being a cache key.
+ */
+ void _markAsCacheKey(AnalysisTarget target) {
+ if (target is ElementImpl) {
+ target.setModifier(Modifier.CACHE_KEY, true);
+ }
+ }
+
+ /**
* Set the [dependedOn] on which this result depends.
*/
void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 1603fac..7815864 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -269,8 +269,6 @@
options.enableStrictCallChecks ||
this._options.enableGenericMethods != options.enableGenericMethods ||
this._options.enableAsync != options.enableAsync ||
- this._options.enableConditionalDirectives !=
- options.enableConditionalDirectives ||
this._options.enableSuperMixins != options.enableSuperMixins;
int cacheSize = options.cacheSize;
if (this._options.cacheSize != cacheSize) {
@@ -285,8 +283,6 @@
this._options.enableAssertMessage = options.enableAssertMessage;
this._options.enableStrictCallChecks = options.enableStrictCallChecks;
this._options.enableAsync = options.enableAsync;
- this._options.enableConditionalDirectives =
- options.enableConditionalDirectives;
this._options.enableSuperMixins = options.enableSuperMixins;
this._options.enableTiming = options.enableTiming;
this._options.hint = options.hint;
@@ -378,8 +374,7 @@
List<Source> sources = <Source>[];
for (Source source in _cache.sources) {
CacheEntry entry = _cache.get(source);
- if (source is Source &&
- entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
+ if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
!source.isInSystemLibrary &&
isServerLibrary(source)) {
sources.add(source);
@@ -813,13 +808,14 @@
CacheEntry entry = _cache.get(target);
if (entry == null) {
entry = new CacheEntry(target);
+ ImplicitAnalysisEvent event = null;
if (target is Source) {
entry.modificationTime = getModificationStamp(target);
+ event = new ImplicitAnalysisEvent(target, true);
}
_cache.put(entry);
- if (target is Source) {
- _implicitAnalysisEventsController
- .add(new ImplicitAnalysisEvent(target, true));
+ if (event != null) {
+ _implicitAnalysisEventsController.add(event);
}
}
return entry;
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 4555a80..78daa6f 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -766,17 +766,14 @@
if (propagatedElement != null) {
executableElement = propagatedElement;
} else {
- if (_leftHandSide is Identifier) {
- Identifier identifier = _leftHandSide as Identifier;
- Element leftElement = identifier.propagatedElement;
+ Expression left = _leftHandSide;
+ if (left is Identifier) {
+ Element leftElement = left.propagatedElement;
if (leftElement is ExecutableElement) {
executableElement = leftElement;
}
- }
- if (_leftHandSide is PropertyAccess) {
- SimpleIdentifier identifier =
- (_leftHandSide as PropertyAccess).propertyName;
- Element leftElement = identifier.propagatedElement;
+ } else if (left is PropertyAccess) {
+ Element leftElement = left.propertyName.propagatedElement;
if (leftElement is ExecutableElement) {
executableElement = leftElement;
}
@@ -803,15 +800,14 @@
if (staticElement != null) {
executableElement = staticElement;
} else {
- if (_leftHandSide is Identifier) {
- Element leftElement = (_leftHandSide as Identifier).staticElement;
+ Expression left = _leftHandSide;
+ if (left is Identifier) {
+ Element leftElement = left.staticElement;
if (leftElement is ExecutableElement) {
executableElement = leftElement;
}
- }
- if (_leftHandSide is PropertyAccess) {
- Element leftElement =
- (_leftHandSide as PropertyAccess).propertyName.staticElement;
+ } else if (left is PropertyAccess) {
+ Element leftElement = left.propertyName.staticElement;
if (leftElement is ExecutableElement) {
executableElement = leftElement;
}
@@ -3228,14 +3224,10 @@
}
@override
- bool get isConst =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
+ bool get isConst => keyword?.keyword == Keyword.CONST;
@override
- bool get isFinal =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
+ bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
TypeName get type => _type;
@@ -3391,8 +3383,7 @@
* The element associated with this directive, or `null` if the AST structure
* has not been resolved or if this directive could not be resolved.
*/
- @override
- Element element;
+ Element _element;
/**
* Initialize a newly create directive. Either or both of the [comment] and
@@ -3401,6 +3392,16 @@
*/
DirectiveImpl(Comment comment, List<Annotation> metadata)
: super(comment, metadata);
+
+ @override
+ Element get element => _element;
+
+ /**
+ * Set the element associated with this directive to be the given [element].
+ */
+ void set element(Element element) {
+ _element = element;
+ }
}
/**
@@ -4356,14 +4357,10 @@
}
@override
- bool get isConst =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
+ bool get isConst => keyword?.keyword == Keyword.CONST;
@override
- bool get isFinal =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
+ bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
FormalParameterList get parameters => _parameters;
@@ -5028,14 +5025,10 @@
}
@override
- bool get isGetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.GET;
+ bool get isGetter => propertyKeyword?.keyword == Keyword.GET;
@override
- bool get isSetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.SET;
+ bool get isSetter => propertyKeyword?.keyword == Keyword.SET;
@override
TypeName get returnType => _returnType;
@@ -6117,9 +6110,7 @@
Token get endToken => _argumentList.endToken;
@override
- bool get isConst =>
- keyword is KeywordToken &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
+ bool get isConst => keyword?.keyword == Keyword.CONST;
@override
int get precedence => 16;
@@ -7116,22 +7107,16 @@
}
@override
- bool get isGetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.GET;
+ bool get isGetter => propertyKeyword?.keyword == Keyword.GET;
@override
bool get isOperator => operatorKeyword != null;
@override
- bool get isSetter =>
- propertyKeyword != null &&
- (propertyKeyword as KeywordToken).keyword == Keyword.SET;
+ bool get isSetter => propertyKeyword?.keyword == Keyword.SET;
@override
- bool get isStatic =>
- modifierKeyword != null &&
- (modifierKeyword as KeywordToken).keyword == Keyword.STATIC;
+ bool get isStatic => modifierKeyword?.keyword == Keyword.STATIC;
@override
SimpleIdentifier get name => _name;
@@ -8248,16 +8233,15 @@
@override
bool get isDeferred {
Element element = _prefix.staticElement;
- if (element is! PrefixElement) {
- return false;
+ if (element is PrefixElement) {
+ List<ImportElement> imports =
+ element.enclosingElement.getImportsWithPrefix(element);
+ if (imports.length != 1) {
+ return false;
+ }
+ return imports[0].isDeferred;
}
- PrefixElement prefixElement = element as PrefixElement;
- List<ImportElement> imports =
- prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
- if (imports.length != 1) {
- return false;
- }
- return imports[0].isDeferred;
+ return false;
}
@override
@@ -8835,14 +8819,10 @@
Token get endToken => identifier.endToken;
@override
- bool get isConst =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
+ bool get isConst => keyword?.keyword == Keyword.CONST;
@override
- bool get isFinal =>
- (keyword is KeywordToken) &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
+ bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
TypeName get type => _type;
@@ -8929,11 +8909,9 @@
AstNode parent = this.parent;
if (parent is PrefixedIdentifier) {
return identical(parent.identifier, this);
- }
- if (parent is PropertyAccess) {
+ } else if (parent is PropertyAccess) {
return identical(parent.propertyName, this);
- }
- if (parent is MethodInvocation) {
+ } else if (parent is MethodInvocation) {
MethodInvocation invocation = parent;
return identical(invocation.methodName, this) &&
invocation.realTarget != null;
@@ -8976,23 +8954,22 @@
@override
bool inGetterContext() {
// TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
+ AstNode initialParent = this.parent;
+ AstNode parent = initialParent;
AstNode target = this;
// skip prefix
- if (parent is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
- if (identical(prefixed.prefix, this)) {
+ if (initialParent is PrefixedIdentifier) {
+ if (identical(initialParent.prefix, this)) {
return true;
}
- parent = prefixed.parent;
- target = prefixed;
- } else if (parent is PropertyAccess) {
- PropertyAccess access = parent as PropertyAccess;
- if (identical(access.target, this)) {
+ parent = initialParent.parent;
+ target = initialParent;
+ } else if (initialParent is PropertyAccess) {
+ if (identical(initialParent.target, this)) {
return true;
}
- parent = access.parent;
- target = access;
+ parent = initialParent.parent;
+ target = initialParent;
}
// skip label
if (parent is Label) {
@@ -9016,24 +8993,23 @@
@override
bool inSetterContext() {
// TODO(brianwilkerson) Convert this to a getter.
- AstNode parent = this.parent;
+ AstNode initialParent = this.parent;
+ AstNode parent = initialParent;
AstNode target = this;
// skip prefix
- if (parent is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
+ if (initialParent is PrefixedIdentifier) {
// if this is the prefix, then return false
- if (identical(prefixed.prefix, this)) {
+ if (identical(initialParent.prefix, this)) {
return false;
}
- parent = prefixed.parent;
- target = prefixed;
- } else if (parent is PropertyAccess) {
- PropertyAccess access = parent as PropertyAccess;
- if (identical(access.target, this)) {
+ parent = initialParent.parent;
+ target = initialParent;
+ } else if (initialParent is PropertyAccess) {
+ if (identical(initialParent.target, this)) {
return false;
}
- parent = access.parent;
- target = access;
+ parent = initialParent.parent;
+ target = initialParent;
}
// analyze usage
if (parent is PrefixExpression) {
@@ -10578,7 +10554,7 @@
super._childEntities..add(_name)..add(equals)..add(_initializer);
/**
- * This overridden implementation of getDocumentationComment() looks in the
+ * This overridden implementation of [documentationComment] looks in the
* grandparent node for Dartdoc comments if no documentation is specifically
* available on the node.
*/
@@ -10586,11 +10562,9 @@
Comment get documentationComment {
Comment comment = super.documentationComment;
if (comment == null) {
- if (parent != null && parent.parent != null) {
- AstNode node = parent.parent;
- if (node is AnnotatedNode) {
- return node.documentationComment;
- }
+ AstNode node = parent?.parent;
+ if (node is AnnotatedNode) {
+ return node.documentationComment;
}
}
return comment;
@@ -10715,14 +10689,10 @@
}
@override
- bool get isConst =>
- keyword is KeywordToken &&
- (keyword as KeywordToken).keyword == Keyword.CONST;
+ bool get isConst => keyword?.keyword == Keyword.CONST;
@override
- bool get isFinal =>
- keyword is KeywordToken &&
- (keyword as KeywordToken).keyword == Keyword.FINAL;
+ bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
TypeName get type => _type;
diff --git a/pkg/analyzer/lib/src/dart/ast/token.dart b/pkg/analyzer/lib/src/dart/ast/token.dart
index 1791990..39a3ab5 100644
--- a/pkg/analyzer/lib/src/dart/ast/token.dart
+++ b/pkg/analyzer/lib/src/dart/ast/token.dart
@@ -142,9 +142,7 @@
* A token representing a keyword in the language.
*/
class KeywordToken extends SimpleToken {
- /**
- * The keyword being represented by this token.
- */
+ @override
final Keyword keyword;
/**
@@ -253,6 +251,9 @@
bool get isUserDefinableOperator => type.isUserDefinableOperator;
@override
+ Keyword get keyword => null;
+
+ @override
int get length => lexeme.length;
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index edd0196..a87c085 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -933,9 +933,10 @@
if (token == null) {
return;
}
- if (token is CommentToken) {
- token = (token as CommentToken).parent;
+ Token nonComment(Token token) {
+ return token is CommentToken ? token.parent : token;
}
+ token = nonComment(token);
if (_lastCloned == null) {
_lastCloned = new Token(TokenType.EOF, -1);
_lastCloned.setNext(_lastCloned);
@@ -2268,7 +2269,7 @@
if (leftOperand is num && rightOperand is num) {
return leftOperand ~/ rightOperand;
}
- } else {}
+ }
break;
}
// TODO(brianwilkerson) This doesn't handle numeric conversions.
@@ -2315,10 +2316,11 @@
for (MapLiteralEntry entry in node.entries) {
Object key = entry.key.accept(this);
Object value = entry.value.accept(this);
- if (key is! String || identical(value, NOT_A_CONSTANT)) {
+ if (key is String && !identical(value, NOT_A_CONSTANT)) {
+ map[(key as String)] = value;
+ } else {
return NOT_A_CONSTANT;
}
- map[(key as String)] = value;
}
return map;
}
@@ -2411,17 +2413,17 @@
*/
Object _getConstantValue(Element element) {
// TODO(brianwilkerson) Implement this
- if (element is FieldElement) {
- FieldElement field = element;
- if (field.isStatic && field.isConst) {
- //field.getConstantValue();
- }
- // } else if (element instanceof VariableElement) {
- // VariableElement variable = (VariableElement) element;
- // if (variable.isStatic() && variable.isConst()) {
- // //variable.getConstantValue();
- // }
- }
+// if (element is FieldElement) {
+// FieldElement field = element;
+// if (field.isStatic && field.isConst) {
+// //field.getConstantValue();
+// }
+// // } else if (element instanceof VariableElement) {
+// // VariableElement variable = (VariableElement) element;
+// // if (variable.isStatic() && variable.isConst()) {
+// // //variable.getConstantValue();
+// // }
+// }
return NOT_A_CONSTANT;
}
}
@@ -2504,17 +2506,14 @@
@override
Element visitIdentifier(Identifier node) {
AstNode parent = node.parent;
- // Type name in Annotation
if (parent is Annotation) {
- Annotation annotation = parent;
- if (identical(annotation.name, node) &&
- annotation.constructorName == null) {
- return annotation.element;
+ // Type name in Annotation
+ if (identical(parent.name, node) && parent.constructorName == null) {
+ return parent.element;
}
- }
- // Extra work to map Constructor Declarations to their associated
- // Constructor Elements
- if (parent is ConstructorDeclaration) {
+ } else if (parent is ConstructorDeclaration) {
+ // Extra work to map Constructor Declarations to their associated
+ // Constructor Elements
Identifier returnType = parent.returnType;
if (identical(returnType, node)) {
SimpleIdentifier name = parent.name;
@@ -2526,8 +2525,7 @@
return element.unnamedConstructor;
}
}
- }
- if (parent is LibraryIdentifier) {
+ } else if (parent is LibraryIdentifier) {
AstNode grandParent = parent.parent;
if (grandParent is PartOfDirective) {
Element element = grandParent.element;
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 2bf03d5..7f0a7b8 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -115,17 +115,18 @@
return false;
}
if (argumentCount == 2) {
- if (arguments[1] is! NamedExpression) {
- return false;
- }
- if (!((arguments[1] as NamedExpression).name.label.name ==
- _DEFAULT_VALUE_PARAM)) {
- return false;
- }
- ParameterizedType defaultValueType =
- namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
- if (!(identical(defaultValueType, expectedDefaultValueType) ||
- identical(defaultValueType, typeProvider.nullType))) {
+ Expression secondArgument = arguments[1];
+ if (secondArgument is NamedExpression) {
+ if (!(secondArgument.name.label.name == _DEFAULT_VALUE_PARAM)) {
+ return false;
+ }
+ ParameterizedType defaultValueType =
+ namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
+ if (!(identical(defaultValueType, expectedDefaultValueType) ||
+ identical(defaultValueType, typeProvider.nullType))) {
+ return false;
+ }
+ } else {
return false;
}
}
@@ -620,13 +621,11 @@
NodeList<Expression> superArguments = null;
for (ConstructorInitializer initializer in initializers) {
if (initializer is ConstructorFieldInitializer) {
- ConstructorFieldInitializer constructorFieldInitializer = initializer;
- Expression initializerExpression =
- constructorFieldInitializer.expression;
+ Expression initializerExpression = initializer.expression;
DartObjectImpl evaluationResult =
initializerExpression.accept(initializerVisitor);
if (evaluationResult != null) {
- String fieldName = constructorFieldInitializer.fieldName.name;
+ String fieldName = initializer.fieldName.name;
if (fieldMap.containsKey(fieldName)) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
@@ -645,12 +644,11 @@
}
}
} else if (initializer is SuperConstructorInvocation) {
- SuperConstructorInvocation superConstructorInvocation = initializer;
- SimpleIdentifier name = superConstructorInvocation.constructorName;
+ SimpleIdentifier name = initializer.constructorName;
if (name != null) {
superName = name.name;
}
- superArguments = superConstructorInvocation.argumentList.arguments;
+ superArguments = initializer.argumentList.arguments;
} else if (initializer is RedirectingConstructorInvocation) {
// This is a redirecting constructor, so just evaluate the constructor
// it redirects to.
@@ -1333,11 +1331,10 @@
DartObjectImpl visitMethodInvocation(MethodInvocation node) {
Element element = node.methodName.staticElement;
if (element is FunctionElement) {
- FunctionElement function = element;
- if (function.name == "identical") {
+ if (element.name == "identical") {
NodeList<Expression> arguments = node.argumentList.arguments;
if (arguments.length == 2) {
- Element enclosingElement = function.enclosingElement;
+ Element enclosingElement = element.enclosingElement;
if (enclosingElement is CompilationUnitElement) {
LibraryElement library = enclosingElement.library;
if (library.isDartCore) {
@@ -1488,17 +1485,15 @@
* reported.
*/
DartObjectImpl _getConstantValue(AstNode node, Element element) {
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- if (element is VariableElementImpl) {
- VariableElementImpl variableElementImpl = element;
- evaluationEngine.validator.beforeGetEvaluationResult(element);
- EvaluationResultImpl value = variableElementImpl.evaluationResult;
- if (variableElementImpl.isConst && value != null) {
+ Element variableElement =
+ element is PropertyAccessorElement ? element.variable : element;
+ if (variableElement is VariableElementImpl) {
+ evaluationEngine.validator.beforeGetEvaluationResult(variableElement);
+ EvaluationResultImpl value = variableElement.evaluationResult;
+ if (variableElement.isConst && value != null) {
return value.value;
}
- } else if (element is ExecutableElement) {
+ } else if (variableElement is ExecutableElement) {
ExecutableElement function = element;
if (function.isStatic) {
ParameterizedType functionType = function.type;
@@ -1507,9 +1502,9 @@
}
return new DartObjectImpl(functionType, new FunctionState(function));
}
- } else if (element is ClassElement ||
- element is FunctionTypeAliasElement ||
- element is DynamicElementImpl) {
+ } else if (variableElement is ClassElement ||
+ variableElement is FunctionTypeAliasElement ||
+ variableElement is DynamicElementImpl) {
return new DartObjectImpl(_typeProvider.typeType, new TypeState(element));
}
// TODO(brianwilkerson) Figure out which error to report.
diff --git a/pkg/analyzer/lib/src/dart/constant/utilities.dart b/pkg/analyzer/lib/src/dart/constant/utilities.dart
index c324d7f..80e736b 100644
--- a/pkg/analyzer/lib/src/dart/constant/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/constant/utilities.dart
@@ -290,10 +290,10 @@
@override
Object visitSimpleIdentifier(SimpleIdentifier node) {
- Element element = node.staticElement;
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
+ Element staticElement = node.staticElement;
+ Element element = staticElement is PropertyAccessorElement
+ ? staticElement.variable
+ : staticElement;
if (element is VariableElement && element.isConst) {
_callback(element);
}
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index 6ebb45d..a269925 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -214,11 +214,10 @@
@override
bool operator ==(Object object) {
- if (object is! DartObjectImpl) {
- return false;
+ if (object is DartObjectImpl) {
+ return type == object.type && _state == object._state;
}
- DartObjectImpl dartObject = object as DartObjectImpl;
- return type == dartObject.type && _state == dartObject._state;
+ return false;
}
/**
@@ -372,8 +371,9 @@
@override
DartObject getField(String name) {
- if (_state is GenericState) {
- return (_state as GenericState).fields[name];
+ InstanceState state = _state;
+ if (state is GenericState) {
+ return state.fields[name];
}
return null;
}
@@ -652,40 +652,45 @@
@override
bool toBoolValue() {
- if (_state is BoolState) {
- return (_state as BoolState).value;
+ InstanceState state = _state;
+ if (state is BoolState) {
+ return state.value;
}
return null;
}
@override
double toDoubleValue() {
- if (_state is DoubleState) {
- return (_state as DoubleState).value;
+ InstanceState state = _state;
+ if (state is DoubleState) {
+ return state.value;
}
return null;
}
@override
int toIntValue() {
- if (_state is IntState) {
- return (_state as IntState).value;
+ InstanceState state = _state;
+ if (state is IntState) {
+ return state.value;
}
return null;
}
@override
List<DartObject> toListValue() {
- if (_state is ListState) {
- return (_state as ListState)._elements;
+ InstanceState state = _state;
+ if (state is ListState) {
+ return state._elements;
}
return null;
}
@override
Map<DartObject, DartObject> toMapValue() {
- if (_state is MapState) {
- return (_state as MapState)._entries;
+ InstanceState state = _state;
+ if (state is MapState) {
+ return state._entries;
}
return null;
}
@@ -695,24 +700,27 @@
@override
String toStringValue() {
- if (_state is StringState) {
- return (_state as StringState).value;
+ InstanceState state = _state;
+ if (state is StringState) {
+ return state.value;
}
return null;
}
@override
String toSymbolValue() {
- if (_state is SymbolState) {
- return (_state as SymbolState).value;
+ InstanceState state = _state;
+ if (state is SymbolState) {
+ return state.value;
}
return null;
}
@override
DartType toTypeValue() {
- if (_state is TypeState) {
- Element element = (_state as TypeState)._element;
+ InstanceState state = _state;
+ if (state is TypeState) {
+ Element element = state._element;
if (element is TypeDefiningElement) {
return element.type;
}
@@ -1346,24 +1354,23 @@
@override
bool operator ==(Object object) {
- if (object is! GenericState) {
- return false;
- }
- GenericState state = object as GenericState;
- HashSet<String> otherFields =
- new HashSet<String>.from(state._fieldMap.keys.toSet());
- for (String fieldName in _fieldMap.keys.toSet()) {
- if (_fieldMap[fieldName] != state._fieldMap[fieldName]) {
- return false;
+ if (object is GenericState) {
+ HashSet<String> otherFields =
+ new HashSet<String>.from(object._fieldMap.keys.toSet());
+ for (String fieldName in _fieldMap.keys.toSet()) {
+ if (_fieldMap[fieldName] != object._fieldMap[fieldName]) {
+ return false;
+ }
+ otherFields.remove(fieldName);
}
- otherFields.remove(fieldName);
- }
- for (String fieldName in otherFields) {
- if (state._fieldMap[fieldName] != _fieldMap[fieldName]) {
- return false;
+ for (String fieldName in otherFields) {
+ if (object._fieldMap[fieldName] != _fieldMap[fieldName]) {
+ return false;
+ }
}
+ return true;
}
- return true;
+ return false;
}
@override
@@ -2299,22 +2306,22 @@
@override
bool operator ==(Object object) {
- if (object is! ListState) {
- return false;
- }
- List<DartObjectImpl> otherElements = (object as ListState)._elements;
- int count = _elements.length;
- if (otherElements.length != count) {
- return false;
- } else if (count == 0) {
+ if (object is ListState) {
+ List<DartObjectImpl> otherElements = object._elements;
+ int count = _elements.length;
+ if (otherElements.length != count) {
+ return false;
+ } else if (count == 0) {
+ return true;
+ }
+ for (int i = 0; i < count; i++) {
+ if (_elements[i] != otherElements[i]) {
+ return false;
+ }
+ }
return true;
}
- for (int i = 0; i < count; i++) {
- if (_elements[i] != otherElements[i]) {
- return false;
- }
- }
- return true;
+ return false;
}
@override
@@ -2381,25 +2388,24 @@
@override
bool operator ==(Object object) {
- if (object is! MapState) {
- return false;
- }
- HashMap<DartObjectImpl, DartObjectImpl> otherElements =
- (object as MapState)._entries;
- int count = _entries.length;
- if (otherElements.length != count) {
- return false;
- } else if (count == 0) {
+ if (object is MapState) {
+ HashMap<DartObjectImpl, DartObjectImpl> otherElements = object._entries;
+ int count = _entries.length;
+ if (otherElements.length != count) {
+ return false;
+ } else if (count == 0) {
+ return true;
+ }
+ for (DartObjectImpl key in _entries.keys) {
+ DartObjectImpl value = _entries[key];
+ DartObjectImpl otherValue = otherElements[key];
+ if (value != otherValue) {
+ return false;
+ }
+ }
return true;
}
- for (DartObjectImpl key in _entries.keys) {
- DartObjectImpl value = _entries[key];
- DartObjectImpl otherValue = otherElements[key];
- if (value != otherValue) {
- return false;
- }
- }
- return true;
+ return false;
}
@override
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 2803273..08de907 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -74,6 +74,11 @@
final LibraryElementImpl libraryElement;
/**
+ * Map from sources referenced by this library to their modification times.
+ */
+ final Map<Source, int> sourceModificationTimeMap;
+
+ /**
* Map from sources imported by this library to their corresponding library
* elements.
*/
@@ -126,6 +131,7 @@
DirectiveElementBuilder(
this.context,
this.libraryElement,
+ this.sourceModificationTimeMap,
this.importLibraryMap,
this.importSourceKindMap,
this.exportLibraryMap,
@@ -163,7 +169,8 @@
// Remove previous element. (It will remain null if the target is missing.)
node.element = null;
Source exportedSource = node.source;
- if (exportedSource != null && context.exists(exportedSource)) {
+ int exportedTime = sourceModificationTimeMap[exportedSource] ?? -1;
+ if (exportedTime != -1) {
// The exported source will be null if the URI in the export
// directive was invalid.
LibraryElement exportedLibrary = exportLibraryMap[exportedSource];
@@ -205,7 +212,8 @@
// Remove previous element. (It will remain null if the target is missing.)
node.element = null;
Source importedSource = node.source;
- if (importedSource != null && context.exists(importedSource)) {
+ int importedTime = sourceModificationTimeMap[importedSource] ?? -1;
+ if (importedTime != -1) {
// The imported source will be null if the URI in the import
// directive was invalid.
LibraryElement importedLibrary = importLibraryMap[importedSource];
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 63528f1b..567c6fe 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -463,29 +463,33 @@
// expected types.
//
for (PropertyAccessorElement accessor in _accessors) {
- if ((accessor as PropertyAccessorElementImpl).identifier == identifier) {
- return accessor as PropertyAccessorElementImpl;
+ PropertyAccessorElementImpl accessorImpl = accessor;
+ if (accessorImpl.identifier == identifier) {
+ return accessorImpl;
}
}
for (ConstructorElement constructor in _constructors) {
- if ((constructor as ConstructorElementImpl).identifier == identifier) {
- return constructor as ConstructorElementImpl;
+ ConstructorElementImpl constructorImpl = constructor;
+ if (constructorImpl.identifier == identifier) {
+ return constructorImpl;
}
}
for (FieldElement field in _fields) {
- if ((field as FieldElementImpl).identifier == identifier) {
- return field as FieldElementImpl;
+ FieldElementImpl fieldImpl = field;
+ if (fieldImpl.identifier == identifier) {
+ return fieldImpl;
}
}
for (MethodElement method in _methods) {
- if ((method as MethodElementImpl).identifier == identifier) {
- return method as MethodElementImpl;
+ MethodElementImpl methodImpl = method;
+ if (methodImpl.identifier == identifier) {
+ return methodImpl;
}
}
for (TypeParameterElement typeParameter in _typeParameters) {
- if ((typeParameter as TypeParameterElementImpl).identifier ==
- identifier) {
- return typeParameter as TypeParameterElementImpl;
+ TypeParameterElementImpl typeParameterImpl = typeParameter;
+ if (typeParameterImpl.identifier == identifier) {
+ return typeParameterImpl;
}
}
return null;
@@ -778,11 +782,12 @@
_internalLookUpSetter(setterName, library, includeThisClass);
while (setter != null && setter.isAbstract) {
Element definingClass = setter.enclosingElement;
- if (definingClass is! ClassElementImpl) {
+ if (definingClass is ClassElementImpl) {
+ setter =
+ definingClass._internalLookUpSetter(setterName, library, false);
+ } else {
return null;
}
- setter = (definingClass as ClassElementImpl)
- ._internalLookUpSetter(setterName, library, false);
}
return setter;
}
@@ -1154,34 +1159,39 @@
// expected types.
//
for (PropertyAccessorElement accessor in _accessors) {
- if ((accessor as PropertyAccessorElementImpl).identifier == identifier) {
- return accessor as PropertyAccessorElementImpl;
+ PropertyAccessorElementImpl accessorImpl = accessor;
+ if (accessorImpl.identifier == identifier) {
+ return accessorImpl;
}
}
- for (VariableElement variable in _variables) {
- if ((variable as VariableElementImpl).identifier == identifier) {
- return variable as VariableElementImpl;
+ for (TopLevelVariableElement variable in _variables) {
+ TopLevelVariableElementImpl variableImpl = variable;
+ if (variableImpl.identifier == identifier) {
+ return variableImpl;
}
}
- for (ExecutableElement function in _functions) {
- if ((function as ExecutableElementImpl).identifier == identifier) {
- return function as ExecutableElementImpl;
+ for (FunctionElement function in _functions) {
+ FunctionElementImpl functionImpl = function;
+ if (functionImpl.identifier == identifier) {
+ return functionImpl;
}
}
for (FunctionTypeAliasElement typeAlias in _typeAliases) {
- if ((typeAlias as FunctionTypeAliasElementImpl).identifier ==
- identifier) {
- return typeAlias as FunctionTypeAliasElementImpl;
+ FunctionTypeAliasElementImpl typeAliasImpl = typeAlias;
+ if (typeAliasImpl.identifier == identifier) {
+ return typeAliasImpl;
}
}
for (ClassElement type in _types) {
- if ((type as ClassElementImpl).identifier == identifier) {
- return type as ClassElementImpl;
+ ClassElementImpl typeImpl = type;
+ if (typeImpl.identifier == identifier) {
+ return typeImpl;
}
}
for (ClassElement type in _enums) {
- if ((type as ClassElementImpl).identifier == identifier) {
- return type as ClassElementImpl;
+ ClassElementImpl typeImpl = type;
+ if (typeImpl.identifier == identifier) {
+ return typeImpl;
}
}
return null;
@@ -1718,9 +1728,10 @@
}
@override
- bool get isJS => element is ConstructorElement &&
- element.enclosingElement.name == _JS_CLASS_NAME &&
- element.library?.name == _JS_LIB_NAME;
+ bool get isJS =>
+ element is ConstructorElement &&
+ element.enclosingElement.name == _JS_CLASS_NAME &&
+ element.library?.name == _JS_LIB_NAME;
@override
bool get isMustCallSuper =>
@@ -2333,21 +2344,20 @@
if (identical(this, object)) {
return true;
}
- if (object is! ElementLocationImpl) {
- return false;
- }
- ElementLocationImpl location = object as ElementLocationImpl;
- List<String> otherComponents = location._components;
- int length = _components.length;
- if (otherComponents.length != length) {
- return false;
- }
- for (int i = 0; i < length; i++) {
- if (_components[i] != otherComponents[i]) {
+ if (object is ElementLocationImpl) {
+ List<String> otherComponents = object._components;
+ int length = _components.length;
+ if (otherComponents.length != length) {
return false;
}
+ for (int i = 0; i < length; i++) {
+ if (_components[i] != otherComponents[i]) {
+ return false;
+ }
+ }
+ return true;
}
- return true;
+ return false;
}
@override
@@ -2593,7 +2603,7 @@
if (i > 0) {
buffer.write(", ");
}
- ParameterElementImpl parameter = _parameters[i] as ParameterElementImpl;
+ ParameterElement parameter = _parameters[i];
ParameterKind parameterKind = parameter.parameterKind;
if (parameterKind != kind) {
if (closing != null) {
@@ -2625,24 +2635,28 @@
@override
ElementImpl getChild(String identifier) {
- for (ExecutableElement function in _functions) {
- if ((function as ExecutableElementImpl).identifier == identifier) {
- return function as ExecutableElementImpl;
+ for (FunctionElement function in _functions) {
+ FunctionElementImpl functionImpl = function;
+ if (functionImpl.identifier == identifier) {
+ return functionImpl;
}
}
for (LabelElement label in _labels) {
- if ((label as LabelElementImpl).identifier == identifier) {
- return label as LabelElementImpl;
+ LabelElementImpl labelImpl = label;
+ if (labelImpl.identifier == identifier) {
+ return labelImpl;
}
}
- for (VariableElement variable in _localVariables) {
- if ((variable as VariableElementImpl).identifier == identifier) {
- return variable as VariableElementImpl;
+ for (LocalVariableElement variable in _localVariables) {
+ LocalVariableElementImpl variableImpl = variable;
+ if (variableImpl.identifier == identifier) {
+ return variableImpl;
}
}
for (ParameterElement parameter in _parameters) {
- if ((parameter as ParameterElementImpl).identifier == identifier) {
- return parameter as ParameterElementImpl;
+ ParameterElementImpl parameterImpl = parameter;
+ if (parameterImpl.identifier == identifier) {
+ return parameterImpl;
}
}
return null;
@@ -3023,15 +3037,16 @@
@override
ElementImpl getChild(String identifier) {
- for (VariableElement parameter in _parameters) {
- if ((parameter as VariableElementImpl).identifier == identifier) {
- return parameter as VariableElementImpl;
+ for (ParameterElement parameter in _parameters) {
+ ParameterElementImpl parameterImpl = parameter;
+ if (parameterImpl.identifier == identifier) {
+ return parameterImpl;
}
}
for (TypeParameterElement typeParameter in _typeParameters) {
- if ((typeParameter as TypeParameterElementImpl).identifier ==
- identifier) {
- return typeParameter as TypeParameterElementImpl;
+ TypeParameterElementImpl typeParameterImpl = typeParameter;
+ if (typeParameterImpl.identifier == identifier) {
+ return typeParameterImpl;
}
}
return null;
@@ -3283,18 +3298,18 @@
@override
int get codeLength {
- if (_definingCompilationUnit is CompilationUnitElementImpl) {
- return (_definingCompilationUnit as CompilationUnitElementImpl)
- .codeLength;
+ CompilationUnitElement unit = _definingCompilationUnit;
+ if (unit is CompilationUnitElementImpl) {
+ return unit.codeLength;
}
return null;
}
@override
int get codeOffset {
- if (_definingCompilationUnit is CompilationUnitElementImpl) {
- return (_definingCompilationUnit as CompilationUnitElementImpl)
- .codeOffset;
+ CompilationUnitElement unit = _definingCompilationUnit;
+ if (unit is CompilationUnitElementImpl) {
+ return unit.codeOffset;
}
return null;
}
@@ -3596,23 +3611,26 @@
@override
ElementImpl getChild(String identifier) {
- if ((_definingCompilationUnit as CompilationUnitElementImpl).identifier ==
- identifier) {
- return _definingCompilationUnit as CompilationUnitElementImpl;
+ CompilationUnitElementImpl unitImpl = _definingCompilationUnit;
+ if (unitImpl.identifier == identifier) {
+ return unitImpl;
}
for (CompilationUnitElement part in _parts) {
- if ((part as CompilationUnitElementImpl).identifier == identifier) {
- return part as CompilationUnitElementImpl;
+ CompilationUnitElementImpl partImpl = part;
+ if (partImpl.identifier == identifier) {
+ return partImpl;
}
}
for (ImportElement importElement in _imports) {
- if ((importElement as ImportElementImpl).identifier == identifier) {
- return importElement as ImportElementImpl;
+ ImportElementImpl importElementImpl = importElement;
+ if (importElementImpl.identifier == identifier) {
+ return importElementImpl;
}
}
for (ExportElement exportElement in _exports) {
- if ((exportElement as ExportElementImpl).identifier == identifier) {
- return exportElement as ExportElementImpl;
+ ExportElementImpl exportElementImpl = exportElement;
+ if (exportElementImpl.identifier == identifier) {
+ return exportElementImpl;
}
}
return null;
@@ -3684,15 +3702,13 @@
// are in the case where library cycles have simply never been computed from
// a newly reachable node.
Set<LibraryElementImpl> active = new HashSet();
- void invalidate(LibraryElement library) {
- if (library is LibraryElementHandle) {
- library = (library as LibraryElementHandle).actualElement;
- }
- LibraryElementImpl libraryImpl = library;
- if (active.add(libraryImpl)) {
- if (libraryImpl._libraryCycle != null) {
- libraryImpl._libraryCycle.forEach(invalidate);
- libraryImpl._libraryCycle = null;
+ void invalidate(LibraryElement element) {
+ LibraryElementImpl library =
+ element is LibraryElementHandle ? element.actualElement : element;
+ if (active.add(library)) {
+ if (library._libraryCycle != null) {
+ library._libraryCycle.forEach(invalidate);
+ library._libraryCycle = null;
}
library.exportedLibraries.forEach(invalidate);
library.importedLibraries.forEach(invalidate);
@@ -3917,10 +3933,8 @@
@override
String get name {
String name = super.name;
- if (isOperator && name == "-") {
- if (parameters.length == 0) {
- return "unary-";
- }
+ if (name == '-' && parameters.isEmpty) {
+ return 'unary-';
}
return super.name;
}
@@ -4485,8 +4499,9 @@
@override
ElementImpl getChild(String identifier) {
for (ParameterElement parameter in _parameters) {
- if ((parameter as ParameterElementImpl).identifier == identifier) {
- return parameter as ParameterElementImpl;
+ ParameterElementImpl parameterImpl = parameter;
+ if (parameterImpl.identifier == identifier) {
+ return parameterImpl;
}
}
return null;
@@ -4702,8 +4717,7 @@
}
if (enclosingElement is ClassElement) {
return getNodeMatching((node) => node is MethodDeclaration);
- }
- if (enclosingElement is CompilationUnitElement) {
+ } else if (enclosingElement is CompilationUnitElement) {
return getNodeMatching((node) => node is FunctionDeclaration);
}
return null;
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 475383e..14e459e 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -68,6 +68,137 @@
}
/**
+ * The type created internally if a circular reference is ever detected in a
+ * function type.
+ */
+class CircularFunctionTypeImpl extends DynamicTypeImpl
+ implements FunctionTypeImpl {
+ CircularFunctionTypeImpl() : super._circular();
+
+ @override
+ List<ParameterElement> get baseParameters => ParameterElement.EMPTY_LIST;
+
+ @override
+ DartType get baseReturnType => DynamicTypeImpl.instance;
+
+ @override
+ List<TypeParameterElement> get boundTypeParameters =>
+ TypeParameterElement.EMPTY_LIST;
+
+ @override
+ FunctionTypedElement get element => super.element;
+
+ @override
+ bool get isInstantiated => false;
+
+ @override
+ Map<String, DartType> get namedParameterTypes => <String, DartType>{};
+
+ @override
+ List<FunctionTypeAliasElement> get newPrune =>
+ FunctionTypeAliasElement.EMPTY_LIST;
+
+ @override
+ List<String> get normalParameterNames => <String>[];
+
+ @override
+ List<DartType> get normalParameterTypes => DartType.EMPTY_LIST;
+
+ @override
+ List<String> get optionalParameterNames => <String>[];
+
+ @override
+ List<DartType> get optionalParameterTypes => DartType.EMPTY_LIST;
+
+ @override
+ List<ParameterElement> get parameters => ParameterElement.EMPTY_LIST;
+
+ @override
+ List<FunctionTypeAliasElement> get prunedTypedefs =>
+ FunctionTypeAliasElement.EMPTY_LIST;
+
+ @override
+ DartType get returnType => DynamicTypeImpl.instance;
+
+ @override
+ List<DartType> get typeArguments => DartType.EMPTY_LIST;
+
+ @override
+ List<TypeParameterElement> get typeFormals => TypeParameterElement.EMPTY_LIST;
+
+ @override
+ List<TypeParameterElement> get typeParameters =>
+ TypeParameterElement.EMPTY_LIST;
+
+ @override
+ bool get _isInstantiated => false;
+
+ @override
+ List<DartType> get _typeArguments => DartType.EMPTY_LIST;
+
+ @override
+ void set _typeArguments(List<DartType> arguments) {
+ throw new UnsupportedError('Cannot have type arguments');
+ }
+
+ @override
+ List<TypeParameterElement> get _typeParameters =>
+ TypeParameterElement.EMPTY_LIST;
+
+ @override
+ void set _typeParameters(List<TypeParameterElement> parameters) {
+ throw new UnsupportedError('Cannot have type parameters');
+ }
+
+ @override
+ bool operator ==(Object object) => object is CircularFunctionTypeImpl;
+
+ @override
+ void appendTo(StringBuffer buffer) {
+ buffer.write('...');
+ }
+
+ @override
+ FunctionTypeImpl instantiate(List<DartType> argumentTypes) => this;
+
+ @override
+ FunctionTypeImpl pruned(List<FunctionTypeAliasElement> prune) => this;
+
+ @override
+ FunctionType substitute2(
+ List<DartType> argumentTypes, List<DartType> parameterTypes,
+ [List<FunctionTypeAliasElement> prune]) {
+ return this;
+ }
+
+ @override
+ FunctionTypeImpl substitute3(List<DartType> argumentTypes) => this;
+
+ @override
+ void _forEachParameterType(
+ ParameterKind kind, callback(String name, DartType type)) {
+ // There are no parameters.
+ }
+
+ @override
+ void _freeVariablesInFunctionType(
+ FunctionType type, Set<TypeParameterType> free) {
+ // There are no free variables
+ }
+
+ @override
+ void _freeVariablesInInterfaceType(
+ InterfaceType type, Set<TypeParameterType> free) {
+ // There are no free variables
+ }
+
+ @override
+ void _freeVariablesInType(DartType type, Set<TypeParameterType> free) {
+ // There are no free variables
+ }
+}
+
+/**
* Type created internally if a circular reference is ever detected. Behaves
* like `dynamic`, except that when converted to a string it is displayed as
* `...`.
@@ -76,9 +207,6 @@
CircularTypeImpl() : super._circular();
@override
- int get hashCode => 1;
-
- @override
bool operator ==(Object object) => object is CircularTypeImpl;
@override
@@ -290,15 +418,15 @@
List<DartType> optionalParameterTypes = this.optionalParameterTypes;
Iterable<DartType> namedParameterTypes = this.namedParameterTypes.values;
// Generate the hashCode
- int code = (returnType as TypeImpl).hashCode;
+ int code = returnType.hashCode;
for (int i = 0; i < normalParameterTypes.length; i++) {
- code = (code << 1) + (normalParameterTypes[i] as TypeImpl).hashCode;
+ code = (code << 1) + normalParameterTypes[i].hashCode;
}
for (int i = 0; i < optionalParameterTypes.length; i++) {
- code = (code << 1) + (optionalParameterTypes[i] as TypeImpl).hashCode;
+ code = (code << 1) + optionalParameterTypes[i].hashCode;
}
for (DartType type in namedParameterTypes) {
- code = (code << 1) + (type as TypeImpl).hashCode;
+ code = (code << 1) + type.hashCode;
}
return code;
}
@@ -484,32 +612,30 @@
@override
bool operator ==(Object object) {
- if (object is! FunctionTypeImpl) {
- return false;
- }
- FunctionTypeImpl otherType = object as FunctionTypeImpl;
- if (typeFormals.length != otherType.typeFormals.length) {
- return false;
- }
- // `<T>T -> T` should be equal to `<U>U -> U`
- // To test this, we instantiate both types with the same (unique) type
- // variables, and see if the result is equal.
- if (typeFormals.isNotEmpty) {
- List<DartType> freshVariables =
- relateTypeFormals(this, otherType, (t, s) => t == s);
- if (freshVariables == null) {
+ if (object is FunctionTypeImpl) {
+ if (typeFormals.length != object.typeFormals.length) {
return false;
}
- return instantiate(freshVariables) ==
- otherType.instantiate(freshVariables);
+ // `<T>T -> T` should be equal to `<U>U -> U`
+ // To test this, we instantiate both types with the same (unique) type
+ // variables, and see if the result is equal.
+ if (typeFormals.isNotEmpty) {
+ List<DartType> freshVariables =
+ relateTypeFormals(this, object, (t, s) => t == s);
+ if (freshVariables == null) {
+ return false;
+ }
+ return instantiate(freshVariables) ==
+ object.instantiate(freshVariables);
+ }
+ return returnType == object.returnType &&
+ TypeImpl.equalArrays(
+ normalParameterTypes, object.normalParameterTypes) &&
+ TypeImpl.equalArrays(
+ optionalParameterTypes, object.optionalParameterTypes) &&
+ _equals(namedParameterTypes, object.namedParameterTypes);
}
-
- return returnType == otherType.returnType &&
- TypeImpl.equalArrays(
- normalParameterTypes, otherType.normalParameterTypes) &&
- TypeImpl.equalArrays(
- optionalParameterTypes, otherType.optionalParameterTypes) &&
- _equals(namedParameterTypes, otherType.namedParameterTypes);
+ return false;
}
@override
@@ -675,12 +801,12 @@
}
@override
- TypeImpl pruned(List<FunctionTypeAliasElement> prune) {
+ FunctionTypeImpl pruned(List<FunctionTypeAliasElement> prune) {
if (prune == null) {
return this;
} else if (prune.contains(element)) {
// Circularity found. Prune the type declaration.
- return new CircularTypeImpl();
+ return new CircularFunctionTypeImpl();
} else {
// There should never be a reason to prune a type that has already been
// pruned, since pruning is only done when expanding a function type
@@ -696,7 +822,7 @@
}
@override
- DartType substitute2(
+ FunctionType substitute2(
List<DartType> argumentTypes, List<DartType> parameterTypes,
[List<FunctionTypeAliasElement> prune]) {
// Pruned types should only ever result from performing type variable
@@ -710,7 +836,7 @@
Element element = this.element;
if (prune != null && prune.contains(element)) {
// Circularity found. Prune the type declaration.
- return new CircularTypeImpl();
+ return new CircularFunctionTypeImpl();
}
if (argumentTypes.length == 0) {
return this.pruned(prune);
@@ -804,7 +930,7 @@
FunctionType t,
DartType other,
bool parameterRelation(DartType t, DartType s),
- FunctionType instantiateToBounds(FunctionType t),
+ DartType instantiateToBounds(DartType t),
{bool returnRelation(DartType t, DartType s)}) {
returnRelation ??= parameterRelation;
@@ -1182,12 +1308,11 @@
if (identical(object, this)) {
return true;
}
- if (object is! InterfaceTypeImpl) {
- return false;
+ if (object is InterfaceTypeImpl) {
+ return (element == object.element) &&
+ TypeImpl.equalArrays(typeArguments, object.typeArguments);
}
- InterfaceTypeImpl otherType = object as InterfaceTypeImpl;
- return (element == otherType.element) &&
- TypeImpl.equalArrays(typeArguments, otherType.typeArguments);
+ return false;
}
@override
@@ -2104,7 +2229,7 @@
bool isAssignableTo(DartType type) {
// An interface type T may be assigned to a type S, written T <=> S, iff
// either T <: S or S <: T.
- return isSubtypeOf(type) || (type as TypeImpl).isSubtypeOf(this);
+ return isSubtypeOf(type) || type.isSubtypeOf(this);
}
/**
diff --git a/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart b/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
new file mode 100644
index 0000000..76cedf7
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
@@ -0,0 +1,1239 @@
+// Copyright (c) 2016, 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:collection';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Instances of the class `InheritanceManager` manage the knowledge of where class members
+ * (methods, getters & setters) are inherited from.
+ */
+class InheritanceManager {
+ /**
+ * The [LibraryElement] that is managed by this manager.
+ */
+ LibraryElement _library;
+
+ /**
+ * This is a mapping between each [ClassElement] and a map between the [String] member
+ * names and the associated [ExecutableElement] in the mixin and superclass chain.
+ */
+ Map<ClassElement, Map<String, ExecutableElement>> _classLookup;
+
+ /**
+ * This is a mapping between each [ClassElement] and a map between the [String] member
+ * names and the associated [ExecutableElement] in the interface set.
+ */
+ Map<ClassElement, Map<String, ExecutableElement>> _interfaceLookup;
+
+ /**
+ * A map between each visited [ClassElement] and the set of [AnalysisError]s found on
+ * the class element.
+ */
+ Map<ClassElement, Set<AnalysisError>> _errorsInClassElement =
+ new HashMap<ClassElement, Set<AnalysisError>>();
+
+ /**
+ * Initialize a newly created inheritance manager.
+ *
+ * @param library the library element context that the inheritance mappings are being generated
+ */
+ InheritanceManager(LibraryElement library) {
+ this._library = library;
+ _classLookup = new HashMap<ClassElement, Map<String, ExecutableElement>>();
+ _interfaceLookup =
+ new HashMap<ClassElement, Map<String, ExecutableElement>>();
+ }
+
+ /**
+ * Set the new library element context.
+ *
+ * @param library the new library element
+ */
+ void set libraryElement(LibraryElement library) {
+ this._library = library;
+ }
+
+ /**
+ * Return the set of [AnalysisError]s found on the passed [ClassElement], or
+ * `null` if there are none.
+ *
+ * @param classElt the class element to query
+ * @return the set of [AnalysisError]s found on the passed [ClassElement], or
+ * `null` if there are none
+ */
+ Set<AnalysisError> getErrors(ClassElement classElt) =>
+ _errorsInClassElement[classElt];
+
+ /**
+ * Get and return a mapping between the set of all string names of the members inherited from the
+ * passed [ClassElement] superclass hierarchy, and the associated [ExecutableElement].
+ *
+ * @param classElt the class element to query
+ * @return a mapping between the set of all members inherited from the passed [ClassElement]
+ * superclass hierarchy, and the associated [ExecutableElement]
+ */
+ @deprecated
+ MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) =>
+ new MemberMap.fromMap(
+ _computeClassChainLookupMap(classElt, new HashSet<ClassElement>()));
+
+ /**
+ * Get and return a mapping between the set of all string names of the members inherited from the
+ * passed [ClassElement] interface hierarchy, and the associated [ExecutableElement].
+ *
+ * @param classElt the class element to query
+ * @return a mapping between the set of all string names of the members inherited from the passed
+ * [ClassElement] interface hierarchy, and the associated [ExecutableElement].
+ */
+ @deprecated
+ MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) =>
+ new MemberMap.fromMap(
+ _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>()));
+
+ /**
+ * Return a table mapping the string names of the members inherited from the
+ * passed [ClassElement]'s superclass hierarchy, and the associated executable
+ * element.
+ */
+ Map<String, ExecutableElement> getMembersInheritedFromClasses(
+ ClassElement classElt) =>
+ _computeClassChainLookupMap(classElt, new HashSet<ClassElement>());
+
+ /**
+ * Return a table mapping the string names of the members inherited from the
+ * passed [ClassElement]'s interface hierarchy, and the associated executable
+ * element.
+ */
+ Map<String, ExecutableElement> getMembersInheritedFromInterfaces(
+ ClassElement classElt) =>
+ _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>());
+
+ /**
+ * Given some [ClassElement] and some member name, this returns the
+ * [ExecutableElement] that the class inherits from the mixins,
+ * superclasses or interfaces, that has the member name, if no member is inherited `null` is
+ * returned.
+ *
+ * @param classElt the class element to query
+ * @param memberName the name of the executable element to find and return
+ * @return the inherited executable element with the member name, or `null` if no such
+ * member exists
+ */
+ ExecutableElement lookupInheritance(
+ ClassElement classElt, String memberName) {
+ if (memberName == null || memberName.isEmpty) {
+ return null;
+ }
+ ExecutableElement executable = _computeClassChainLookupMap(
+ classElt, new HashSet<ClassElement>())[memberName];
+ if (executable == null) {
+ return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>())[
+ memberName];
+ }
+ return executable;
+ }
+
+ /**
+ * Given some [ClassElement] and some member name, this returns the
+ * [ExecutableElement] that the class either declares itself, or
+ * inherits, that has the member name, if no member is inherited `null` is returned.
+ *
+ * @param classElt the class element to query
+ * @param memberName the name of the executable element to find and return
+ * @return the inherited executable element with the member name, or `null` if no such
+ * member exists
+ */
+ ExecutableElement lookupMember(ClassElement classElt, String memberName) {
+ ExecutableElement element = _lookupMemberInClass(classElt, memberName);
+ if (element != null) {
+ return element;
+ }
+ return lookupInheritance(classElt, memberName);
+ }
+
+ /**
+ * Determine the set of methods which is overridden by the given class member. If no member is
+ * inherited, an empty list is returned. If one of the inherited members is a
+ * [MultiplyInheritedExecutableElement], then it is expanded into its constituent inherited
+ * elements.
+ *
+ * @param classElt the class to query
+ * @param memberName the name of the class member to query
+ * @return a list of overridden methods
+ */
+ List<ExecutableElement> lookupOverrides(
+ ClassElement classElt, String memberName) {
+ List<ExecutableElement> result = new List<ExecutableElement>();
+ if (memberName == null || memberName.isEmpty) {
+ return result;
+ }
+ List<Map<String, ExecutableElement>> interfaceMaps =
+ _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>());
+ if (interfaceMaps != null) {
+ for (Map<String, ExecutableElement> interfaceMap in interfaceMaps) {
+ ExecutableElement overriddenElement = interfaceMap[memberName];
+ if (overriddenElement != null) {
+ if (overriddenElement is MultiplyInheritedExecutableElement) {
+ for (ExecutableElement element
+ in overriddenElement.inheritedElements) {
+ result.add(element);
+ }
+ } else {
+ result.add(overriddenElement);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This method takes some inherited [FunctionType], and resolves all the parameterized types
+ * in the function type, dependent on the class in which it is being overridden.
+ *
+ * @param baseFunctionType the function type that is being overridden
+ * @param memberName the name of the member, this is used to lookup the inheritance path of the
+ * override
+ * @param definingType the type that is overriding the member
+ * @return the passed function type with any parameterized types substituted
+ */
+ // TODO(jmesserly): investigate why this is needed in ErrorVerifier's override
+ // checking. There seems to be some rare cases where we get partially
+ // substituted type arguments, and the function types don't compare equally.
+ FunctionType substituteTypeArgumentsInMemberFromInheritance(
+ FunctionType baseFunctionType,
+ String memberName,
+ InterfaceType definingType) {
+ // if the baseFunctionType is null, or does not have any parameters,
+ // return it.
+ if (baseFunctionType == null ||
+ baseFunctionType.typeArguments.length == 0) {
+ return baseFunctionType;
+ }
+ // First, generate the path from the defining type to the overridden member
+ Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
+ _computeInheritancePath(inheritancePath, definingType, memberName);
+ if (inheritancePath == null || inheritancePath.isEmpty) {
+ // TODO(jwren) log analysis engine error
+ return baseFunctionType;
+ }
+ FunctionType functionTypeToReturn = baseFunctionType;
+ // loop backward through the list substituting as we go:
+ while (!inheritancePath.isEmpty) {
+ InterfaceType lastType = inheritancePath.removeLast();
+ List<DartType> parameterTypes = lastType.element.type.typeArguments;
+ List<DartType> argumentTypes = lastType.typeArguments;
+ functionTypeToReturn =
+ functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
+ }
+ return functionTypeToReturn;
+ }
+
+ /**
+ * Compute and return a mapping between the set of all string names of the members inherited from
+ * the passed [ClassElement] superclass hierarchy, and the associated
+ * [ExecutableElement].
+ *
+ * @param classElt the class element to query
+ * @param visitedClasses a set of visited classes passed back into this method when it calls
+ * itself recursively
+ * @return a mapping between the set of all string names of the members inherited from the passed
+ * [ClassElement] superclass hierarchy, and the associated [ExecutableElement]
+ */
+ Map<String, ExecutableElement> _computeClassChainLookupMap(
+ ClassElement classElt, Set<ClassElement> visitedClasses) {
+ Map<String, ExecutableElement> resultMap = _classLookup[classElt];
+ if (resultMap != null) {
+ return resultMap;
+ } else {
+ resultMap = new Map<String, ExecutableElement>();
+ }
+ ClassElement superclassElt = null;
+ InterfaceType supertype = classElt.supertype;
+ if (supertype != null) {
+ superclassElt = supertype.element;
+ } else {
+ // classElt is Object
+ _classLookup[classElt] = resultMap;
+ return resultMap;
+ }
+ if (superclassElt != null) {
+ if (!visitedClasses.contains(superclassElt)) {
+ visitedClasses.add(superclassElt);
+ try {
+ resultMap = new Map<String, ExecutableElement>.from(
+ _computeClassChainLookupMap(superclassElt, visitedClasses));
+ //
+ // Substitute the super types down the hierarchy.
+ //
+ _substituteTypeParametersDownHierarchy(supertype, resultMap);
+ //
+ // Include the members from the superclass in the resultMap.
+ //
+ _recordMapWithClassMembers(resultMap, supertype, false);
+ } finally {
+ visitedClasses.remove(superclassElt);
+ }
+ } else {
+ // This case happens only when the superclass was previously visited and
+ // not in the lookup, meaning this is meant to shorten the compute for
+ // recursive cases.
+ _classLookup[superclassElt] = resultMap;
+ return resultMap;
+ }
+ }
+ //
+ // Include the members from the mixins in the resultMap. If there are
+ // multiple mixins, visit them in the order listed so that methods in later
+ // mixins will overwrite identically-named methods in earlier mixins.
+ //
+ List<InterfaceType> mixins = classElt.mixins;
+ for (InterfaceType mixin in mixins) {
+ ClassElement mixinElement = mixin.element;
+ if (mixinElement != null) {
+ if (!visitedClasses.contains(mixinElement)) {
+ visitedClasses.add(mixinElement);
+ try {
+ Map<String, ExecutableElement> map =
+ new Map<String, ExecutableElement>.from(
+ _computeClassChainLookupMap(mixinElement, visitedClasses));
+ //
+ // Substitute the super types down the hierarchy.
+ //
+ _substituteTypeParametersDownHierarchy(mixin, map);
+ //
+ // Include the members from the superclass in the resultMap.
+ //
+ _recordMapWithClassMembers(map, mixin, false);
+ //
+ // Add the members from map into result map.
+ //
+ for (String memberName in map.keys) {
+ ExecutableElement value = map[memberName];
+ ClassElement definingClass = value
+ .getAncestor((Element element) => element is ClassElement);
+ if (!definingClass.type.isObject) {
+ ExecutableElement existingValue = resultMap[memberName];
+ if (existingValue == null ||
+ (existingValue != null && !_isAbstract(value))) {
+ resultMap[memberName] = value;
+ }
+ }
+ }
+ } finally {
+ visitedClasses.remove(mixinElement);
+ }
+ } else {
+ // This case happens only when the superclass was previously visited
+ // and not in the lookup, meaning this is meant to shorten the compute
+ // for recursive cases.
+ _classLookup[mixinElement] = resultMap;
+ return resultMap;
+ }
+ }
+ }
+ _classLookup[classElt] = resultMap;
+ return resultMap;
+ }
+
+ /**
+ * Compute and return the inheritance path given the context of a type and a member that is
+ * overridden in the inheritance path (for which the type is in the path).
+ *
+ * @param chain the inheritance path that is built up as this method calls itself recursively,
+ * when this method is called an empty [LinkedList] should be provided
+ * @param currentType the current type in the inheritance path
+ * @param memberName the name of the member that is being looked up the inheritance path
+ */
+ void _computeInheritancePath(Queue<InterfaceType> chain,
+ InterfaceType currentType, String memberName) {
+ // TODO (jwren) create a public version of this method which doesn't require
+ // the initial chain to be provided, then provided tests for this
+ // functionality in InheritanceManagerTest
+ chain.add(currentType);
+ ClassElement classElt = currentType.element;
+ InterfaceType supertype = classElt.supertype;
+ // Base case- reached Object
+ if (supertype == null) {
+ // Looked up the chain all the way to Object, return null.
+ // This should never happen.
+ return;
+ }
+ // If we are done, return the chain
+ // We are not done if this is the first recursive call on this method.
+ if (chain.length != 1) {
+ // We are done however if the member is in this classElt
+ if (_lookupMemberInClass(classElt, memberName) != null) {
+ return;
+ }
+ }
+ // Mixins- note that mixins call lookupMemberInClass, not lookupMember
+ List<InterfaceType> mixins = classElt.mixins;
+ for (int i = mixins.length - 1; i >= 0; i--) {
+ ClassElement mixinElement = mixins[i].element;
+ if (mixinElement != null) {
+ ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
+ if (elt != null) {
+ // this is equivalent (but faster than) calling this method
+ // recursively
+ // (return computeInheritancePath(chain, mixins[i], memberName);)
+ chain.add(mixins[i]);
+ return;
+ }
+ }
+ }
+ // Superclass
+ ClassElement superclassElt = supertype.element;
+ if (lookupMember(superclassElt, memberName) != null) {
+ _computeInheritancePath(chain, supertype, memberName);
+ return;
+ }
+ // Interfaces
+ List<InterfaceType> interfaces = classElt.interfaces;
+ for (InterfaceType interfaceType in interfaces) {
+ ClassElement interfaceElement = interfaceType.element;
+ if (interfaceElement != null &&
+ lookupMember(interfaceElement, memberName) != null) {
+ _computeInheritancePath(chain, interfaceType, memberName);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Compute and return a mapping between the set of all string names of the members inherited from
+ * the passed [ClassElement] interface hierarchy, and the associated
+ * [ExecutableElement].
+ *
+ * @param classElt the class element to query
+ * @param visitedInterfaces a set of visited classes passed back into this method when it calls
+ * itself recursively
+ * @return a mapping between the set of all string names of the members inherited from the passed
+ * [ClassElement] interface hierarchy, and the associated [ExecutableElement]
+ */
+ Map<String, ExecutableElement> _computeInterfaceLookupMap(
+ ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
+ Map<String, ExecutableElement> resultMap = _interfaceLookup[classElt];
+ if (resultMap != null) {
+ return resultMap;
+ }
+ List<Map<String, ExecutableElement>> lookupMaps =
+ _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
+ if (lookupMaps == null) {
+ resultMap = new Map<String, ExecutableElement>();
+ } else {
+ HashMap<String, List<ExecutableElement>> unionMap =
+ _unionInterfaceLookupMaps(lookupMaps);
+ resultMap = _resolveInheritanceLookup(classElt, unionMap);
+ }
+ _interfaceLookup[classElt] = resultMap;
+ return resultMap;
+ }
+
+ /**
+ * Collect a list of interface lookup maps whose elements correspond to all of the classes
+ * directly above [classElt] in the class hierarchy (the direct superclass if any, all
+ * mixins, and all direct superinterfaces). Each item in the list is the interface lookup map
+ * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
+ * parameters appropriately substituted.
+ *
+ * @param classElt the class element to query
+ * @param visitedInterfaces a set of visited classes passed back into this method when it calls
+ * itself recursively
+ * @return `null` if there was a problem (such as a loop in the class hierarchy) or if there
+ * are no classes above this one in the class hierarchy. Otherwise, a list of interface
+ * lookup maps.
+ */
+ List<Map<String, ExecutableElement>> _gatherInterfaceLookupMaps(
+ ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
+ InterfaceType supertype = classElt.supertype;
+ ClassElement superclassElement =
+ supertype != null ? supertype.element : null;
+ List<InterfaceType> mixins = classElt.mixins;
+ List<InterfaceType> interfaces = classElt.interfaces;
+ // Recursively collect the list of mappings from all of the interface types
+ List<Map<String, ExecutableElement>> lookupMaps =
+ new List<Map<String, ExecutableElement>>();
+ //
+ // Superclass element
+ //
+ if (superclassElement != null) {
+ if (!visitedInterfaces.contains(superclassElement)) {
+ try {
+ visitedInterfaces.add(superclassElement);
+ //
+ // Recursively compute the map for the super type.
+ //
+ Map<String, ExecutableElement> map =
+ _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
+ map = new Map<String, ExecutableElement>.from(map);
+ //
+ // Substitute the super type down the hierarchy.
+ //
+ _substituteTypeParametersDownHierarchy(supertype, map);
+ //
+ // Add any members from the super type into the map as well.
+ //
+ _recordMapWithClassMembers(map, supertype, true);
+ lookupMaps.add(map);
+ } finally {
+ visitedInterfaces.remove(superclassElement);
+ }
+ } else {
+ return null;
+ }
+ }
+ //
+ // Mixin elements
+ //
+ for (int i = mixins.length - 1; i >= 0; i--) {
+ InterfaceType mixinType = mixins[i];
+ ClassElement mixinElement = mixinType.element;
+ if (mixinElement != null) {
+ if (!visitedInterfaces.contains(mixinElement)) {
+ try {
+ visitedInterfaces.add(mixinElement);
+ //
+ // Recursively compute the map for the mixin.
+ //
+ Map<String, ExecutableElement> map =
+ _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
+ map = new Map<String, ExecutableElement>.from(map);
+ //
+ // Substitute the mixin type down the hierarchy.
+ //
+ _substituteTypeParametersDownHierarchy(mixinType, map);
+ //
+ // Add any members from the mixin type into the map as well.
+ //
+ _recordMapWithClassMembers(map, mixinType, true);
+ lookupMaps.add(map);
+ } finally {
+ visitedInterfaces.remove(mixinElement);
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+ //
+ // Interface elements
+ //
+ for (InterfaceType interfaceType in interfaces) {
+ ClassElement interfaceElement = interfaceType.element;
+ if (interfaceElement != null) {
+ if (!visitedInterfaces.contains(interfaceElement)) {
+ try {
+ visitedInterfaces.add(interfaceElement);
+ //
+ // Recursively compute the map for the interfaces.
+ //
+ Map<String, ExecutableElement> map =
+ _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
+ map = new Map<String, ExecutableElement>.from(map);
+ //
+ // Substitute the supertypes down the hierarchy
+ //
+ _substituteTypeParametersDownHierarchy(interfaceType, map);
+ //
+ // And add any members from the interface into the map as well.
+ //
+ _recordMapWithClassMembers(map, interfaceType, true);
+ lookupMaps.add(map);
+ } finally {
+ visitedInterfaces.remove(interfaceElement);
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+ if (lookupMaps.length == 0) {
+ return null;
+ }
+ return lookupMaps;
+ }
+
+ /**
+ * Given some [ClassElement], this method finds and returns the [ExecutableElement] of
+ * the passed name in the class element. Static members, members in super types and members not
+ * accessible from the current library are not considered.
+ *
+ * @param classElt the class element to query
+ * @param memberName the name of the member to lookup in the class
+ * @return the found [ExecutableElement], or `null` if no such member was found
+ */
+ ExecutableElement _lookupMemberInClass(
+ ClassElement classElt, String memberName) {
+ List<MethodElement> methods = classElt.methods;
+ for (MethodElement method in methods) {
+ if (memberName == method.name &&
+ method.isAccessibleIn(_library) &&
+ !method.isStatic) {
+ return method;
+ }
+ }
+ List<PropertyAccessorElement> accessors = classElt.accessors;
+ for (PropertyAccessorElement accessor in accessors) {
+ if (memberName == accessor.name &&
+ accessor.isAccessibleIn(_library) &&
+ !accessor.isStatic) {
+ return accessor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Record the passed map with the set of all members (methods, getters and setters) in the type
+ * into the passed map.
+ *
+ * @param map some non-`null` map to put the methods and accessors from the passed
+ * [ClassElement] into
+ * @param type the type that will be recorded into the passed map
+ * @param doIncludeAbstract `true` if abstract members will be put into the map
+ */
+ void _recordMapWithClassMembers(Map<String, ExecutableElement> map,
+ InterfaceType type, bool doIncludeAbstract) {
+ List<MethodElement> methods = type.methods;
+ for (MethodElement method in methods) {
+ if (method.isAccessibleIn(_library) &&
+ !method.isStatic &&
+ (doIncludeAbstract || !method.isAbstract)) {
+ map[method.name] = method;
+ }
+ }
+ List<PropertyAccessorElement> accessors = type.accessors;
+ for (PropertyAccessorElement accessor in accessors) {
+ if (accessor.isAccessibleIn(_library) &&
+ !accessor.isStatic &&
+ (doIncludeAbstract || !accessor.isAbstract)) {
+ map[accessor.name] = accessor;
+ }
+ }
+ }
+
+ /**
+ * This method is used to report errors on when they are found computing inheritance information.
+ * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where these generated
+ * error codes are reported back into the analysis engine.
+ *
+ * @param classElt the location of the source for which the exception occurred
+ * @param offset the offset of the location of the error
+ * @param length the length of the location of the error
+ * @param errorCode the error code to be associated with this error
+ * @param arguments the arguments used to build the error message
+ */
+ void _reportError(ClassElement classElt, int offset, int length,
+ ErrorCode errorCode, List<Object> arguments) {
+ HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
+ if (errorSet == null) {
+ errorSet = new HashSet<AnalysisError>();
+ _errorsInClassElement[classElt] = errorSet;
+ }
+ errorSet.add(new AnalysisError(
+ classElt.source, offset, length, errorCode, arguments));
+ }
+
+ /**
+ * Given the set of methods defined by classes above [classElt] in the class hierarchy,
+ * apply the appropriate inheritance rules to determine those methods inherited by or overridden
+ * by [classElt]. Also report static warnings
+ * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
+ * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if appropriate.
+ *
+ * @param classElt the class element to query.
+ * @param unionMap a mapping from method name to the set of unique (in terms of signature) methods
+ * defined in superclasses of [classElt].
+ * @return the inheritance lookup map for [classElt].
+ */
+ Map<String, ExecutableElement> _resolveInheritanceLookup(
+ ClassElement classElt, Map<String, List<ExecutableElement>> unionMap) {
+ Map<String, ExecutableElement> resultMap =
+ new Map<String, ExecutableElement>();
+ unionMap.forEach((String key, List<ExecutableElement> list) {
+ int numOfEltsWithMatchingNames = list.length;
+ if (numOfEltsWithMatchingNames == 1) {
+ //
+ // Example: class A inherits only 1 method named 'm'.
+ // Since it is the only such method, it is inherited.
+ // Another example: class A inherits 2 methods named 'm' from 2
+ // different interfaces, but they both have the same signature, so it is
+ // the method inherited.
+ //
+ resultMap[key] = list[0];
+ } else {
+ //
+ // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
+ //
+ bool allMethods = true;
+ bool allSetters = true;
+ bool allGetters = true;
+ for (ExecutableElement executableElement in list) {
+ if (executableElement is PropertyAccessorElement) {
+ allMethods = false;
+ if (executableElement.isSetter) {
+ allGetters = false;
+ } else {
+ allSetters = false;
+ }
+ } else {
+ allGetters = false;
+ allSetters = false;
+ }
+ }
+ //
+ // If there isn't a mixture of methods with getters, then continue,
+ // otherwise create a warning.
+ //
+ if (allMethods || allGetters || allSetters) {
+ //
+ // Compute the element whose type is the subtype of all of the other
+ // types.
+ //
+ List<ExecutableElement> elements = new List.from(list);
+ List<FunctionType> executableElementTypes =
+ new List<FunctionType>(numOfEltsWithMatchingNames);
+ for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
+ executableElementTypes[i] = elements[i].type;
+ }
+ List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
+ for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
+ FunctionType subtype = executableElementTypes[i];
+ if (subtype == null) {
+ continue;
+ }
+ bool subtypeOfAllTypes = true;
+ TypeSystem typeSystem = _library.context.typeSystem;
+ for (int j = 0;
+ j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
+ j++) {
+ if (i != j) {
+ if (!typeSystem.isSubtypeOf(
+ subtype, executableElementTypes[j])) {
+ subtypeOfAllTypes = false;
+ break;
+ }
+ }
+ }
+ if (subtypeOfAllTypes) {
+ subtypesOfAllOtherTypesIndexes.add(i);
+ }
+ }
+ //
+ // The following is split into three cases determined by the number of
+ // elements in subtypesOfAllOtherTypes
+ //
+ if (subtypesOfAllOtherTypesIndexes.length == 1) {
+ //
+ // Example: class A inherited only 2 method named 'm'.
+ // One has the function type '() -> dynamic' and one has the
+ // function type '([int]) -> dynamic'. Since the second method is a
+ // subtype of all the others, it is the inherited method.
+ // Tests: InheritanceManagerTest.
+ // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
+ //
+ resultMap[key] = elements[subtypesOfAllOtherTypesIndexes[0]];
+ } else {
+ if (subtypesOfAllOtherTypesIndexes.isEmpty) {
+ //
+ // Determine if the current class has a method or accessor with
+ // the member name, if it does then then this class does not
+ // "inherit" from any of the supertypes. See issue 16134.
+ //
+ bool classHasMember = false;
+ if (allMethods) {
+ classHasMember = classElt.getMethod(key) != null;
+ } else {
+ List<PropertyAccessorElement> accessors = classElt.accessors;
+ for (int i = 0; i < accessors.length; i++) {
+ if (accessors[i].name == key) {
+ classHasMember = true;
+ }
+ }
+ }
+ //
+ // Example: class A inherited only 2 method named 'm'.
+ // One has the function type '() -> int' and one has the function
+ // type '() -> String'. Since neither is a subtype of the other,
+ // we create a warning, and have this class inherit nothing.
+ //
+ if (!classHasMember) {
+ String firstTwoFuntionTypesStr =
+ "${executableElementTypes[0]}, ${executableElementTypes[1]}";
+ _reportError(
+ classElt,
+ classElt.nameOffset,
+ classElt.nameLength,
+ StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
+ [key, firstTwoFuntionTypesStr]);
+ }
+ } else {
+ //
+ // Example: class A inherits 2 methods named 'm'.
+ // One has the function type '(int) -> dynamic' and one has the
+ // function type '(num) -> dynamic'. Since they are both a subtype
+ // of the other, a synthetic function '(dynamic) -> dynamic' is
+ // inherited.
+ // Tests: test_getMapOfMembersInheritedFromInterfaces_
+ // union_multipleSubtypes_*
+ //
+ List<ExecutableElement> elementArrayToMerge =
+ new List<ExecutableElement>(
+ subtypesOfAllOtherTypesIndexes.length);
+ for (int i = 0; i < elementArrayToMerge.length; i++) {
+ elementArrayToMerge[i] =
+ elements[subtypesOfAllOtherTypesIndexes[i]];
+ }
+ ExecutableElement mergedExecutableElement =
+ _computeMergedExecutableElement(elementArrayToMerge);
+ resultMap[key] = mergedExecutableElement;
+ }
+ }
+ } else {
+ _reportError(
+ classElt,
+ classElt.nameOffset,
+ classElt.nameLength,
+ StaticWarningCode
+ .INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD,
+ [key]);
+ }
+ }
+ });
+ return resultMap;
+ }
+
+ /**
+ * Loop through all of the members in the given [map], performing type
+ * parameter substitutions using a passed [supertype].
+ */
+ void _substituteTypeParametersDownHierarchy(
+ InterfaceType superType, Map<String, ExecutableElement> map) {
+ for (String memberName in map.keys) {
+ ExecutableElement executableElement = map[memberName];
+ if (executableElement is MethodMember) {
+ map[memberName] = MethodMember.from(executableElement, superType);
+ } else if (executableElement is PropertyAccessorMember) {
+ map[memberName] =
+ PropertyAccessorMember.from(executableElement, superType);
+ }
+ }
+ }
+
+ /**
+ * Union all of the [lookupMaps] together into a single map, grouping the ExecutableElements
+ * into a list where none of the elements are equal where equality is determined by having equal
+ * function types. (We also take note too of the kind of the element: ()->int and () -> int may
+ * not be equal if one is a getter and the other is a method.)
+ *
+ * @param lookupMaps the maps to be unioned together.
+ * @return the resulting union map.
+ */
+ HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
+ List<Map<String, ExecutableElement>> lookupMaps) {
+ HashMap<String, List<ExecutableElement>> unionMap =
+ new HashMap<String, List<ExecutableElement>>();
+ for (Map<String, ExecutableElement> lookupMap in lookupMaps) {
+ for (String memberName in lookupMap.keys) {
+ // Get the list value out of the unionMap
+ List<ExecutableElement> list = unionMap[memberName];
+ // If we haven't created such a map for this key yet, do create it and
+ // put the list entry into the unionMap.
+ if (list == null) {
+ list = new List<ExecutableElement>();
+ unionMap[memberName] = list;
+ }
+ // Fetch the entry out of this lookupMap
+ ExecutableElement newExecutableElementEntry = lookupMap[memberName];
+ if (list.isEmpty) {
+ // If the list is empty, just the new value
+ list.add(newExecutableElementEntry);
+ } else {
+ // Otherwise, only add the newExecutableElementEntry if it isn't
+ // already in the list, this covers situation where a class inherits
+ // two methods (or two getters) that are identical.
+ bool alreadyInList = false;
+ bool isMethod1 = newExecutableElementEntry is MethodElement;
+ for (ExecutableElement executableElementInList in list) {
+ bool isMethod2 = executableElementInList is MethodElement;
+ if (isMethod1 == isMethod2 &&
+ executableElementInList.type ==
+ newExecutableElementEntry.type) {
+ alreadyInList = true;
+ break;
+ }
+ }
+ if (!alreadyInList) {
+ list.add(newExecutableElementEntry);
+ }
+ }
+ }
+ }
+ return unionMap;
+ }
+
+ /**
+ * Given some array of [ExecutableElement]s, this method creates a synthetic element as
+ * described in 8.1.1:
+ *
+ * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional parameters of a
+ * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote the number of
+ * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denote the set of all
+ * named parameters of the <i>m<sub>1</sub>, …, m<sub>k</sub></i>. Then let
+ * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
+ * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
+ * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameters of type
+ * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, named parameters
+ * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
+ *
+ */
+ static ExecutableElement _computeMergedExecutableElement(
+ List<ExecutableElement> elementArrayToMerge) {
+ int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
+ int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
+ Set<String> namedParametersList = new HashSet<String>();
+ for (int i = 1; i < elementArrayToMerge.length; i++) {
+ ExecutableElement element = elementArrayToMerge[i];
+ int numOfPositionalParams = _getNumOfPositionalParameters(element);
+ if (h < numOfPositionalParams) {
+ h = numOfPositionalParams;
+ }
+ int numOfRequiredParams = _getNumOfRequiredParameters(element);
+ if (r > numOfRequiredParams) {
+ r = numOfRequiredParams;
+ }
+ namedParametersList.addAll(_getNamedParameterNames(element));
+ }
+ return _createSyntheticExecutableElement(
+ elementArrayToMerge,
+ elementArrayToMerge[0].displayName,
+ r,
+ h - r,
+ new List.from(namedParametersList));
+ }
+
+ /**
+ * Used by [computeMergedExecutableElement] to actually create the
+ * synthetic element.
+ *
+ * @param elementArrayToMerge the array used to create the synthetic element
+ * @param name the name of the method, getter or setter
+ * @param numOfRequiredParameters the number of required parameters
+ * @param numOfPositionalParameters the number of positional parameters
+ * @param namedParameters the list of [String]s that are the named parameters
+ * @return the created synthetic element
+ */
+ static ExecutableElement _createSyntheticExecutableElement(
+ List<ExecutableElement> elementArrayToMerge,
+ String name,
+ int numOfRequiredParameters,
+ int numOfPositionalParameters,
+ List<String> namedParameters) {
+ DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
+ SimpleIdentifier nameIdentifier =
+ new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0));
+ ExecutableElementImpl executable;
+ ExecutableElement elementToMerge = elementArrayToMerge[0];
+ if (elementToMerge is MethodElement) {
+ MultiplyInheritedMethodElementImpl unionedMethod =
+ new MultiplyInheritedMethodElementImpl(nameIdentifier);
+ unionedMethod.inheritedElements = elementArrayToMerge;
+ executable = unionedMethod;
+ } else if (elementToMerge is PropertyAccessorElement) {
+ MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
+ new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
+ unionedPropertyAccessor.getter = elementToMerge.isGetter;
+ unionedPropertyAccessor.setter = elementToMerge.isSetter;
+ unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
+ executable = unionedPropertyAccessor;
+ } else {
+ throw new AnalysisException(
+ 'Invalid class of element in merge: ${elementToMerge.runtimeType}');
+ }
+ int numOfParameters = numOfRequiredParameters +
+ numOfPositionalParameters +
+ namedParameters.length;
+ List<ParameterElement> parameters =
+ new List<ParameterElement>(numOfParameters);
+ int i = 0;
+ for (int j = 0; j < numOfRequiredParameters; j++, i++) {
+ ParameterElementImpl parameter = new ParameterElementImpl("", 0);
+ parameter.type = dynamicType;
+ parameter.parameterKind = ParameterKind.REQUIRED;
+ parameters[i] = parameter;
+ }
+ for (int k = 0; k < numOfPositionalParameters; k++, i++) {
+ ParameterElementImpl parameter = new ParameterElementImpl("", 0);
+ parameter.type = dynamicType;
+ parameter.parameterKind = ParameterKind.POSITIONAL;
+ parameters[i] = parameter;
+ }
+ for (int m = 0; m < namedParameters.length; m++, i++) {
+ ParameterElementImpl parameter =
+ new ParameterElementImpl(namedParameters[m], 0);
+ parameter.type = dynamicType;
+ parameter.parameterKind = ParameterKind.NAMED;
+ parameters[i] = parameter;
+ }
+ executable.returnType = dynamicType;
+ executable.parameters = parameters;
+ FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
+ executable.type = methodType;
+ return executable;
+ }
+
+ /**
+ * Given some [ExecutableElement], return the list of named parameters.
+ */
+ static List<String> _getNamedParameterNames(
+ ExecutableElement executableElement) {
+ List<String> namedParameterNames = new List<String>();
+ List<ParameterElement> parameters = executableElement.parameters;
+ for (int i = 0; i < parameters.length; i++) {
+ ParameterElement parameterElement = parameters[i];
+ if (parameterElement.parameterKind == ParameterKind.NAMED) {
+ namedParameterNames.add(parameterElement.name);
+ }
+ }
+ return namedParameterNames;
+ }
+
+ /**
+ * Given some [ExecutableElement] return the number of parameters of the specified kind.
+ */
+ static int _getNumOfParameters(
+ ExecutableElement executableElement, ParameterKind parameterKind) {
+ int parameterCount = 0;
+ List<ParameterElement> parameters = executableElement.parameters;
+ for (int i = 0; i < parameters.length; i++) {
+ ParameterElement parameterElement = parameters[i];
+ if (parameterElement.parameterKind == parameterKind) {
+ parameterCount++;
+ }
+ }
+ return parameterCount;
+ }
+
+ /**
+ * Given some [ExecutableElement] return the number of positional parameters.
+ *
+ * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSITIONAL].
+ */
+ static int _getNumOfPositionalParameters(
+ ExecutableElement executableElement) =>
+ _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
+ _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
+
+ /**
+ * Given some [ExecutableElement] return the number of required parameters.
+ */
+ static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
+ _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
+
+ /**
+ * Given some [ExecutableElement] returns `true` if it is an abstract member of a
+ * class.
+ *
+ * @param executableElement some [ExecutableElement] to evaluate
+ * @return `true` if the given element is an abstract member of a class
+ */
+ static bool _isAbstract(ExecutableElement executableElement) {
+ if (executableElement is MethodElement) {
+ return executableElement.isAbstract;
+ } else if (executableElement is PropertyAccessorElement) {
+ return executableElement.isAbstract;
+ }
+ return false;
+ }
+}
+
+/**
+ * This class is used to replace uses of `HashMap<String, ExecutableElement>`
+ * which are not as performant as this class.
+ */
+@deprecated
+class MemberMap {
+ /**
+ * The current size of this map.
+ */
+ int _size = 0;
+
+ /**
+ * The array of keys.
+ */
+ List<String> _keys;
+
+ /**
+ * The array of ExecutableElement values.
+ */
+ List<ExecutableElement> _values;
+
+ /**
+ * Initialize a newly created member map to have the given [initialCapacity].
+ * The map will grow if needed.
+ */
+ MemberMap([int initialCapacity = 10]) {
+ _initArrays(initialCapacity);
+ }
+
+ /**
+ * Initialize a newly created member map to contain the same members as the
+ * given [memberMap].
+ */
+ MemberMap.from(MemberMap memberMap) {
+ _initArrays(memberMap._size + 5);
+ for (int i = 0; i < memberMap._size; i++) {
+ _keys[i] = memberMap._keys[i];
+ _values[i] = memberMap._values[i];
+ }
+ _size = memberMap._size;
+ }
+
+ /**
+ * Initialize a newly created member map to contain the same members as the
+ * given [map].
+ */
+ MemberMap.fromMap(Map<String, ExecutableElement> map) {
+ _size = map.length;
+ _initArrays(_size + 5);
+ int index = 0;
+ map.forEach((String memberName, ExecutableElement element) {
+ _keys[index] = memberName;
+ _values[index] = element;
+ index++;
+ });
+ }
+
+ /**
+ * The size of the map.
+ *
+ * @return the size of the map.
+ */
+ int get size => _size;
+
+ /**
+ * Given some key, return the ExecutableElement value from the map, if the key does not exist in
+ * the map, `null` is returned.
+ *
+ * @param key some key to look up in the map
+ * @return the associated ExecutableElement value from the map, if the key does not exist in the
+ * map, `null` is returned
+ */
+ ExecutableElement get(String key) {
+ for (int i = 0; i < _size; i++) {
+ if (_keys[i] != null && _keys[i] == key) {
+ return _values[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get and return the key at the specified location. If the key/value pair has been removed from
+ * the set, then `null` is returned.
+ *
+ * @param i some non-zero value less than size
+ * @return the key at the passed index
+ * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than
+ * zero or greater than or equal to the capacity of the arrays
+ */
+ String getKey(int i) => _keys[i];
+
+ /**
+ * Get and return the ExecutableElement at the specified location. If the key/value pair has been
+ * removed from the set, then then `null` is returned.
+ *
+ * @param i some non-zero value less than size
+ * @return the key at the passed index
+ * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than
+ * zero or greater than or equal to the capacity of the arrays
+ */
+ ExecutableElement getValue(int i) => _values[i];
+
+ /**
+ * Given some key/value pair, store the pair in the map. If the key exists already, then the new
+ * value overrides the old value.
+ *
+ * @param key the key to store in the map
+ * @param value the ExecutableElement value to store in the map
+ */
+ void put(String key, ExecutableElement value) {
+ // If we already have a value with this key, override the value
+ for (int i = 0; i < _size; i++) {
+ if (_keys[i] != null && _keys[i] == key) {
+ _values[i] = value;
+ return;
+ }
+ }
+ // If needed, double the size of our arrays and copy values over in both
+ // arrays
+ if (_size == _keys.length) {
+ int newArrayLength = _size * 2;
+ List<String> keys_new_array = new List<String>(newArrayLength);
+ List<ExecutableElement> values_new_array =
+ new List<ExecutableElement>(newArrayLength);
+ for (int i = 0; i < _size; i++) {
+ keys_new_array[i] = _keys[i];
+ }
+ for (int i = 0; i < _size; i++) {
+ values_new_array[i] = _values[i];
+ }
+ _keys = keys_new_array;
+ _values = values_new_array;
+ }
+ // Put new value at end of array
+ _keys[_size] = key;
+ _values[_size] = value;
+ _size++;
+ }
+
+ /**
+ * Given some [String] key, this method replaces the associated key and value pair with
+ * `null`. The size is not decremented with this call, instead it is expected that the users
+ * check for `null`.
+ *
+ * @param key the key of the key/value pair to remove from the map
+ */
+ void remove(String key) {
+ for (int i = 0; i < _size; i++) {
+ if (_keys[i] == key) {
+ _keys[i] = null;
+ _values[i] = null;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Sets the ExecutableElement at the specified location.
+ *
+ * @param i some non-zero value less than size
+ * @param value the ExecutableElement value to store in the map
+ */
+ void setValue(int i, ExecutableElement value) {
+ _values[i] = value;
+ }
+
+ /**
+ * Initializes [keys] and [values].
+ */
+ void _initArrays(int initialCapacity) {
+ _keys = new List<String>(initialCapacity);
+ _values = new List<ExecutableElement>(initialCapacity);
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
new file mode 100644
index 0000000..54086d9
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -0,0 +1,1059 @@
+// 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 analyzer.src.dart.resolver.scope;
+
+import 'dart:collection';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * The scope defined by a class.
+ */
+class ClassScope extends EnclosedScope {
+ /**
+ * Initialize a newly created scope, enclosed within the [enclosingScope],
+ * based on the given [classElement].
+ */
+ ClassScope(Scope enclosingScope, ClassElement classElement)
+ : super(enclosingScope) {
+ if (classElement == null) {
+ throw new IllegalArgumentException("class element cannot be null");
+ }
+ _defineMembers(classElement);
+ }
+
+ @override
+ AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
+ if (existing is PropertyAccessorElement && duplicate is MethodElement) {
+ if (existing.nameOffset < duplicate.nameOffset) {
+ return new AnalysisError(
+ duplicate.source,
+ duplicate.nameOffset,
+ duplicate.nameLength,
+ CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
+ [existing.displayName]);
+ } else {
+ return new AnalysisError(
+ existing.source,
+ existing.nameOffset,
+ existing.nameLength,
+ CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
+ [existing.displayName]);
+ }
+ }
+ return super.getErrorForDuplicate(existing, duplicate);
+ }
+
+ /**
+ * Define the instance members defined by the given [classElement].
+ */
+ void _defineMembers(ClassElement classElement) {
+ for (PropertyAccessorElement accessor in classElement.accessors) {
+ define(accessor);
+ }
+ for (MethodElement method in classElement.methods) {
+ define(method);
+ }
+ }
+}
+
+/**
+ * A scope that is lexically enclosed in another scope.
+ */
+class EnclosedScope extends Scope {
+ /**
+ * The scope in which this scope is lexically enclosed.
+ */
+ @override
+ final Scope enclosingScope;
+
+ /**
+ * A table mapping names that will be defined in this scope, but right now are
+ * not initialized. According to the scoping rules these names are hidden,
+ * even if they were defined in an outer scope.
+ */
+ HashMap<String, Element> _hiddenElements = null;
+
+ /**
+ * Initialize a newly created scope, enclosed within the [enclosingScope].
+ */
+ EnclosedScope(this.enclosingScope);
+
+ @override
+ AnalysisErrorListener get errorListener => enclosingScope.errorListener;
+
+ /**
+ * Record that given [element] is declared in this scope, but hasn't been
+ * initialized yet, so it is error to use. If there is already an element with
+ * the given name defined in an outer scope, then it will become unavailable.
+ */
+ void hide(Element element) {
+ if (element != null) {
+ String name = element.name;
+ if (name != null && !name.isEmpty) {
+ _hiddenElements ??= new HashMap<String, Element>();
+ _hiddenElements[name] = element;
+ }
+ }
+ }
+
+ @override
+ Element internalLookup(
+ Identifier identifier, String name, LibraryElement referencingLibrary) {
+ Element element = localLookup(name, referencingLibrary);
+ if (element != null) {
+ return element;
+ }
+ // May be there is a hidden Element.
+ if (_hiddenElements != null) {
+ Element hiddenElement = _hiddenElements[name];
+ if (hiddenElement != null) {
+ errorListener.onError(new AnalysisError(
+ getSource(identifier),
+ identifier.offset,
+ identifier.length,
+ CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
+ return hiddenElement;
+ }
+ }
+ // Check enclosing scope.
+ return enclosingScope.internalLookup(identifier, name, referencingLibrary);
+ }
+}
+
+/**
+ * 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 the [enclosingScope],
+ * that represents the given [_functionElement].
+ */
+ FunctionScope(Scope enclosingScope, this._functionElement)
+ : 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.
+ */
+ void defineParameters() {
+ if (_parametersDefined) {
+ return;
+ }
+ _parametersDefined = true;
+ Scope parameterScope = enclosingScope;
+ for (ParameterElement parameter in _functionElement.parameters) {
+ if (!parameter.isInitializingFormal) {
+ parameterScope.define(parameter);
+ }
+ }
+ }
+
+ /**
+ * Define the type parameters for the function.
+ */
+ void _defineTypeParameters() {
+ Scope typeParameterScope = enclosingScope.enclosingScope;
+ for (TypeParameterElement typeParameter
+ in _functionElement.typeParameters) {
+ typeParameterScope.define(typeParameter);
+ }
+ }
+}
+
+/**
+ * The scope defined by a function type alias.
+ */
+class FunctionTypeScope extends EnclosedScope {
+ final FunctionTypeAliasElement _typeElement;
+
+ bool _parametersDefined = false;
+
+ /**
+ * Initialize a newly created scope, enclosed within the [enclosingScope],
+ * that represents the given [_typeElement].
+ */
+ FunctionTypeScope(Scope enclosingScope, this._typeElement)
+ : super(new EnclosedScope(enclosingScope)) {
+ _defineTypeParameters();
+ }
+
+ /**
+ * Define the parameters for the function type alias.
+ */
+ void defineParameters() {
+ if (_parametersDefined) {
+ return;
+ }
+ _parametersDefined = true;
+ for (ParameterElement parameter in _typeElement.parameters) {
+ define(parameter);
+ }
+ }
+
+ /**
+ * Define the type parameters for the function type alias.
+ */
+ void _defineTypeParameters() {
+ Scope typeParameterScope = enclosingScope;
+ for (TypeParameterElement typeParameter in _typeElement.typeParameters) {
+ typeParameterScope.define(typeParameter);
+ }
+ }
+}
+
+/**
+ * The scope statements that can be the target of unlabeled `break` and
+ * `continue` statements.
+ */
+class ImplicitLabelScope {
+ /**
+ * The implicit label scope associated with the top level of a function.
+ */
+ static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null);
+
+ /**
+ * The implicit label scope enclosing this implicit label scope.
+ */
+ final ImplicitLabelScope outerScope;
+
+ /**
+ * The statement that acts as a target for break and/or continue statements
+ * at this scoping level.
+ */
+ final Statement statement;
+
+ /**
+ * Initialize a newly created scope, enclosed within the [outerScope],
+ * representing the given [statement].
+ */
+ const ImplicitLabelScope._(this.outerScope, this.statement);
+
+ /**
+ * Return the statement which should be the target of an unlabeled `break` or
+ * `continue` statement, or `null` if there is no appropriate target.
+ */
+ Statement getTarget(bool isContinue) {
+ if (outerScope == null) {
+ // This scope represents the toplevel of a function body, so it doesn't
+ // match either break or continue.
+ return null;
+ }
+ if (isContinue && statement is SwitchStatement) {
+ return outerScope.getTarget(isContinue);
+ }
+ return statement;
+ }
+
+ /**
+ * Initialize a newly created scope to represent a switch statement or loop
+ * nested within the current scope. [statement] is the statement associated
+ * with the newly created scope.
+ */
+ ImplicitLabelScope nest(Statement statement) =>
+ new ImplicitLabelScope._(this, statement);
+}
+
+/**
+ * A scope in which a single label is defined.
+ */
+class LabelScope {
+ /**
+ * The label scope enclosing this label scope.
+ */
+ final LabelScope _outerScope;
+
+ /**
+ * The label defined in this scope.
+ */
+ final String _label;
+
+ /**
+ * The element to which the label resolves.
+ */
+ final LabelElement element;
+
+ /**
+ * The AST node to which the label resolves.
+ */
+ final AstNode node;
+
+ /**
+ * Initialize a newly created scope, enclosed within the [_outerScope],
+ * representing the label [_label]. The [node] is the AST node the label
+ * resolves to. The [element] is the element the label resolves to.
+ */
+ LabelScope(this._outerScope, this._label, this.node, this.element);
+
+ /**
+ * Return the LabelScope which defines [targetLabel], or `null` if it is not
+ * defined in this scope.
+ */
+ LabelScope lookup(String targetLabel) {
+ if (_label == targetLabel) {
+ return this;
+ } else if (_outerScope != null) {
+ return _outerScope.lookup(targetLabel);
+ } else {
+ return null;
+ }
+ }
+}
+
+/**
+ * The scope containing all of the names available from imported libraries.
+ */
+class LibraryImportScope extends Scope {
+ /**
+ * The element representing the library in which this scope is enclosed.
+ */
+ final LibraryElement _definingLibrary;
+
+ /**
+ * The listener that is to be informed when an error is encountered.
+ */
+ @override
+ final AnalysisErrorListener errorListener;
+
+ /**
+ * A list of the namespaces representing the names that are available in this scope from imported
+ * libraries.
+ */
+ List<Namespace> _importedNamespaces;
+
+ /**
+ * Initialize a newly created scope representing the names imported into the
+ * [_definingLibrary]. The [errorListener] is the listener that is to be
+ * informed when an error is encountered.
+ */
+ LibraryImportScope(this._definingLibrary, this.errorListener) {
+ _createImportedNamespaces();
+ }
+
+ @override
+ void define(Element element) {
+ if (!Scope.isPrivateName(element.displayName)) {
+ super.define(element);
+ }
+ }
+
+ @override
+ Source getSource(AstNode node) {
+ Source source = super.getSource(node);
+ if (source == null) {
+ source = _definingLibrary.definingCompilationUnit.source;
+ }
+ return source;
+ }
+
+ @override
+ Element internalLookup(
+ Identifier identifier, String name, LibraryElement referencingLibrary) {
+ Element foundElement = localLookup(name, referencingLibrary);
+ if (foundElement != null) {
+ return foundElement;
+ }
+ for (int i = 0; i < _importedNamespaces.length; i++) {
+ Namespace nameSpace = _importedNamespaces[i];
+ Element element = nameSpace.get(name);
+ if (element != null) {
+ if (foundElement == null) {
+ foundElement = element;
+ } else if (!identical(foundElement, element)) {
+ foundElement = MultiplyDefinedElementImpl.fromElements(
+ _definingLibrary.context, foundElement, element);
+ }
+ }
+ }
+ Element element = foundElement;
+ if (element is MultiplyDefinedElementImpl) {
+ foundElement = _removeSdkElements(identifier, name, element);
+ }
+ if (foundElement is MultiplyDefinedElementImpl) {
+ String foundEltName = foundElement.displayName;
+ List<Element> conflictingMembers = foundElement.conflictingElements;
+ int count = conflictingMembers.length;
+ List<String> libraryNames = new List<String>(count);
+ for (int i = 0; i < count; i++) {
+ libraryNames[i] = _getLibraryName(conflictingMembers[i]);
+ }
+ libraryNames.sort();
+ errorListener.onError(new AnalysisError(
+ getSource(identifier),
+ identifier.offset,
+ identifier.length,
+ StaticWarningCode.AMBIGUOUS_IMPORT, [
+ foundEltName,
+ StringUtilities.printListOfQuotedNames(libraryNames)
+ ]));
+ return foundElement;
+ }
+ if (foundElement != null) {
+ defineNameWithoutChecking(name, foundElement);
+ }
+ return foundElement;
+ }
+
+ /**
+ * Create all of the namespaces associated with the libraries imported into
+ * this library. The names are not added to this scope, but are stored for
+ * later reference.
+ */
+ void _createImportedNamespaces() {
+ NamespaceBuilder builder = new NamespaceBuilder();
+ List<ImportElement> imports = _definingLibrary.imports;
+ int count = imports.length;
+ _importedNamespaces = new List<Namespace>(count);
+ for (int i = 0; i < count; i++) {
+ _importedNamespaces[i] =
+ builder.createImportNamespaceForDirective(imports[i]);
+ }
+ }
+
+ /**
+ * Return the name of the library that defines given [element].
+ */
+ String _getLibraryName(Element element) {
+ if (element == null) {
+ return StringUtilities.EMPTY;
+ }
+ LibraryElement library = element.library;
+ if (library == null) {
+ return StringUtilities.EMPTY;
+ }
+ List<ImportElement> imports = _definingLibrary.imports;
+ int count = imports.length;
+ for (int i = 0; i < count; i++) {
+ if (identical(imports[i].importedLibrary, library)) {
+ return library.definingCompilationUnit.displayName;
+ }
+ }
+ List<String> indirectSources = new List<String>();
+ for (int i = 0; i < count; i++) {
+ LibraryElement importedLibrary = imports[i].importedLibrary;
+ if (importedLibrary != null) {
+ for (LibraryElement exportedLibrary
+ in importedLibrary.exportedLibraries) {
+ if (identical(exportedLibrary, library)) {
+ indirectSources
+ .add(importedLibrary.definingCompilationUnit.displayName);
+ }
+ }
+ }
+ }
+ int indirectCount = indirectSources.length;
+ StringBuffer buffer = new StringBuffer();
+ buffer.write(library.definingCompilationUnit.displayName);
+ if (indirectCount > 0) {
+ buffer.write(" (via ");
+ if (indirectCount > 1) {
+ indirectSources.sort();
+ buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
+ } else {
+ buffer.write(indirectSources[0]);
+ }
+ buffer.write(")");
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Given a collection of elements (captured by the [foundElement]) that the
+ * [identifier] (with the given [name]) resolved to, remove from the list all
+ * of the names defined in the SDK and return the element(s) that remain.
+ */
+ Element _removeSdkElements(Identifier identifier, String name,
+ MultiplyDefinedElementImpl foundElement) {
+ List<Element> conflictingElements = foundElement.conflictingElements;
+ List<Element> nonSdkElements = new List<Element>();
+ Element sdkElement = null;
+ for (Element member in conflictingElements) {
+ if (member.library.isInSdk) {
+ sdkElement = member;
+ } else {
+ nonSdkElements.add(member);
+ }
+ }
+ if (sdkElement != null && nonSdkElements.length > 0) {
+ String sdkLibName = _getLibraryName(sdkElement);
+ String otherLibName = _getLibraryName(nonSdkElements[0]);
+ errorListener.onError(new AnalysisError(
+ getSource(identifier),
+ identifier.offset,
+ identifier.length,
+ StaticWarningCode.CONFLICTING_DART_IMPORT,
+ [name, sdkLibName, otherLibName]));
+ }
+ if (nonSdkElements.length == conflictingElements.length) {
+ // None of the members were removed
+ return foundElement;
+ } else if (nonSdkElements.length == 1) {
+ // All but one member was removed
+ return nonSdkElements[0];
+ } else if (nonSdkElements.length == 0) {
+ // All members were removed
+ AnalysisEngine.instance.logger
+ .logInformation("Multiply defined SDK element: $foundElement");
+ return foundElement;
+ }
+ return new MultiplyDefinedElementImpl(
+ _definingLibrary.context, nonSdkElements);
+ }
+}
+
+/**
+ * A scope containing all of the names defined in a given library.
+ */
+class LibraryScope extends EnclosedScope {
+ /**
+ * Initialize a newly created scope representing the names defined in the
+ * [definingLibrary]. The [errorListener] is the listener that is to be
+ * informed when an error is encountered
+ */
+ LibraryScope(
+ LibraryElement definingLibrary, AnalysisErrorListener errorListener)
+ : super(new LibraryImportScope(definingLibrary, errorListener)) {
+ _defineTopLevelNames(definingLibrary);
+ }
+
+ @override
+ AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
+ if (existing is PrefixElement) {
+ // TODO(scheglov) consider providing actual 'nameOffset' from the
+ // synthetic accessor
+ int offset = duplicate.nameOffset;
+ if (duplicate is PropertyAccessorElement) {
+ PropertyAccessorElement accessor = duplicate;
+ if (accessor.isSynthetic) {
+ offset = accessor.variable.nameOffset;
+ }
+ }
+ return new AnalysisError(
+ duplicate.source,
+ offset,
+ duplicate.nameLength,
+ CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
+ [existing.displayName]);
+ }
+ return super.getErrorForDuplicate(existing, duplicate);
+ }
+
+ /**
+ * Add to this scope all of the public top-level names that are defined in the
+ * given [compilationUnit].
+ */
+ void _defineLocalNames(CompilationUnitElement compilationUnit) {
+ for (PropertyAccessorElement element in compilationUnit.accessors) {
+ define(element);
+ }
+ for (ClassElement element in compilationUnit.enums) {
+ define(element);
+ }
+ for (FunctionElement element in compilationUnit.functions) {
+ define(element);
+ }
+ for (FunctionTypeAliasElement element
+ in compilationUnit.functionTypeAliases) {
+ define(element);
+ }
+ for (ClassElement element in compilationUnit.types) {
+ define(element);
+ }
+ }
+
+ /**
+ * Add to this scope all of the names that are explicitly defined in the
+ * [definingLibrary].
+ */
+ void _defineTopLevelNames(LibraryElement definingLibrary) {
+ for (PrefixElement prefix in definingLibrary.prefixes) {
+ define(prefix);
+ }
+ _defineLocalNames(definingLibrary.definingCompilationUnit);
+ for (CompilationUnitElement compilationUnit in definingLibrary.parts) {
+ _defineLocalNames(compilationUnit);
+ }
+ }
+}
+
+/**
+ * A mapping of identifiers to the elements represented by those identifiers.
+ * Namespaces are the building blocks for scopes.
+ */
+class Namespace {
+ /**
+ * An empty namespace.
+ */
+ static Namespace EMPTY = new Namespace(new HashMap<String, Element>());
+
+ /**
+ * A table mapping names that are defined in this namespace to the element
+ * representing the thing declared with that name.
+ */
+ final HashMap<String, Element> _definedNames;
+
+ /**
+ * Initialize a newly created namespace to have the [_definedNames].
+ */
+ Namespace(this._definedNames);
+
+ /**
+ * Return a table containing the same mappings as those defined by this
+ * namespace.
+ */
+ Map<String, Element> get definedNames => _definedNames;
+
+ /**
+ * Return the element in this namespace that is available to the containing
+ * scope using the given name.
+ */
+ Element get(String name) => _definedNames[name];
+}
+
+/**
+ * The builder used to build a namespace. Namespace builders are thread-safe and
+ * re-usable.
+ */
+class NamespaceBuilder {
+ /**
+ * Create a namespace representing the export namespace of the given [element].
+ */
+ Namespace createExportNamespaceForDirective(ExportElement element) {
+ LibraryElement exportedLibrary = element.exportedLibrary;
+ if (exportedLibrary == null) {
+ //
+ // The exported library will be null if the URI does not reference a valid
+ // library.
+ //
+ return Namespace.EMPTY;
+ }
+ HashMap<String, Element> exportedNames = _getExportMapping(exportedLibrary);
+ exportedNames = _applyCombinators(exportedNames, element.combinators);
+ return new Namespace(exportedNames);
+ }
+
+ /**
+ * Create a namespace representing the export namespace of the given [library].
+ */
+ Namespace createExportNamespaceForLibrary(LibraryElement library) {
+ HashMap<String, Element> exportedNames = _getExportMapping(library);
+ return new Namespace(exportedNames);
+ }
+
+ /**
+ * Create a namespace representing the import namespace of the given [element].
+ */
+ Namespace createImportNamespaceForDirective(ImportElement element) {
+ LibraryElement importedLibrary = element.importedLibrary;
+ if (importedLibrary == null) {
+ //
+ // The imported library will be null if the URI does not reference a valid
+ // library.
+ //
+ return Namespace.EMPTY;
+ }
+ HashMap<String, Element> exportedNames = _getExportMapping(importedLibrary);
+ exportedNames = _applyCombinators(exportedNames, element.combinators);
+ exportedNames = _applyPrefix(exportedNames, element.prefix);
+ return new Namespace(exportedNames);
+ }
+
+ /**
+ * Create a namespace representing the public namespace of the given
+ * [library].
+ */
+ Namespace createPublicNamespaceForLibrary(LibraryElement library) {
+ HashMap<String, Element> definedNames = new HashMap<String, Element>();
+ _addPublicNames(definedNames, library.definingCompilationUnit);
+ for (CompilationUnitElement compilationUnit in library.parts) {
+ _addPublicNames(definedNames, compilationUnit);
+ }
+ return new Namespace(definedNames);
+ }
+
+ /**
+ * Add all of the names in the given [namespace] to the table of
+ * [definedNames].
+ */
+ void _addAllFromNamespace(
+ Map<String, Element> definedNames, Namespace namespace) {
+ if (namespace != null) {
+ definedNames.addAll(namespace.definedNames);
+ }
+ }
+
+ /**
+ * Add the given [element] to the table of [definedNames] if it has a
+ * publicly visible name.
+ */
+ void _addIfPublic(Map<String, Element> definedNames, Element element) {
+ String name = element.name;
+ if (name != null && !Scope.isPrivateName(name)) {
+ definedNames[name] = element;
+ }
+ }
+
+ /**
+ * Add to the table of [definedNames] all of the public top-level names that
+ * are defined in the given [compilationUnit].
+ * namespace
+ */
+ void _addPublicNames(Map<String, Element> definedNames,
+ CompilationUnitElement compilationUnit) {
+ for (PropertyAccessorElement element in compilationUnit.accessors) {
+ _addIfPublic(definedNames, element);
+ }
+ for (ClassElement element in compilationUnit.enums) {
+ _addIfPublic(definedNames, element);
+ }
+ for (FunctionElement element in compilationUnit.functions) {
+ _addIfPublic(definedNames, element);
+ }
+ for (FunctionTypeAliasElement element
+ in compilationUnit.functionTypeAliases) {
+ _addIfPublic(definedNames, element);
+ }
+ for (ClassElement element in compilationUnit.types) {
+ _addIfPublic(definedNames, element);
+ }
+ }
+
+ /**
+ * Apply the given [combinators] to all of the names in the given table of
+ * [definedNames].
+ */
+ HashMap<String, Element> _applyCombinators(
+ HashMap<String, Element> definedNames,
+ List<NamespaceCombinator> combinators) {
+ for (NamespaceCombinator combinator in combinators) {
+ if (combinator is HideElementCombinator) {
+ definedNames = _hide(definedNames, combinator.hiddenNames);
+ } else if (combinator is ShowElementCombinator) {
+ definedNames = _show(definedNames, combinator.shownNames);
+ } else {
+ // Internal error.
+ AnalysisEngine.instance.logger
+ .logError("Unknown type of combinator: ${combinator.runtimeType}");
+ }
+ }
+ return definedNames;
+ }
+
+ /**
+ * Apply the prefix defined by the [prefixElement] to all of the names in the
+ * table of [definedNames].
+ */
+ HashMap<String, Element> _applyPrefix(
+ HashMap<String, Element> definedNames, PrefixElement prefixElement) {
+ if (prefixElement != null) {
+ String prefix = prefixElement.name;
+ HashMap<String, Element> newNames = new HashMap<String, Element>();
+ definedNames.forEach((String name, Element element) {
+ newNames["$prefix.$name"] = element;
+ });
+ return newNames;
+ } else {
+ return definedNames;
+ }
+ }
+
+ /**
+ * Create a mapping table representing the export namespace of the given
+ * [library]. The set of [visitedElements] contains the libraries that do not
+ * need to be visited when processing the export directives of the given
+ * library because all of the names defined by them will be added by another
+ * library.
+ */
+ HashMap<String, Element> _computeExportMapping(
+ LibraryElement library, HashSet<LibraryElement> visitedElements) {
+ visitedElements.add(library);
+ try {
+ HashMap<String, Element> definedNames = new HashMap<String, Element>();
+ for (ExportElement element in library.exports) {
+ LibraryElement exportedLibrary = element.exportedLibrary;
+ if (exportedLibrary != null &&
+ !visitedElements.contains(exportedLibrary)) {
+ //
+ // The exported library will be null if the URI does not reference a
+ // valid library.
+ //
+ HashMap<String, Element> exportedNames =
+ _computeExportMapping(exportedLibrary, visitedElements);
+ exportedNames = _applyCombinators(exportedNames, element.combinators);
+ definedNames.addAll(exportedNames);
+ }
+ }
+ _addAllFromNamespace(
+ definedNames,
+ (library.context as InternalAnalysisContext)
+ .getPublicNamespace(library));
+ return definedNames;
+ } finally {
+ visitedElements.remove(library);
+ }
+ }
+
+ HashMap<String, Element> _getExportMapping(LibraryElement library) {
+ if (library is LibraryElementImpl) {
+ if (library.exportNamespace != null) {
+ return library.exportNamespace.definedNames;
+ } else {
+ HashMap<String, Element> exportMapping =
+ _computeExportMapping(library, new HashSet<LibraryElement>());
+ library.exportNamespace = new Namespace(exportMapping);
+ return exportMapping;
+ }
+ }
+ return _computeExportMapping(library, new HashSet<LibraryElement>());
+ }
+
+ /**
+ * Return a new map of names which has all the names from [definedNames]
+ * with exception of [hiddenNames].
+ */
+ Map<String, Element> _hide(
+ HashMap<String, Element> definedNames, List<String> hiddenNames) {
+ HashMap<String, Element> newNames =
+ new HashMap<String, Element>.from(definedNames);
+ for (String name in hiddenNames) {
+ newNames.remove(name);
+ newNames.remove("$name=");
+ }
+ return newNames;
+ }
+
+ /**
+ * Return a new map of names which has only [shownNames] from [definedNames].
+ */
+ HashMap<String, Element> _show(
+ HashMap<String, Element> definedNames, List<String> shownNames) {
+ HashMap<String, Element> newNames = new HashMap<String, Element>();
+ for (String name in shownNames) {
+ Element element = definedNames[name];
+ if (element != null) {
+ newNames[name] = element;
+ }
+ String setterName = "$name=";
+ element = definedNames[setterName];
+ if (element != null) {
+ newNames[setterName] = element;
+ }
+ }
+ return newNames;
+ }
+}
+
+/**
+ * A name scope used by the resolver to determine which names are visible at any
+ * given point in the code.
+ */
+abstract class Scope {
+ /**
+ * The prefix used to mark an identifier as being private to its library.
+ */
+ static int PRIVATE_NAME_PREFIX = 0x5F;
+
+ /**
+ * The suffix added to the declared name of a setter when looking up the
+ * setter. Used to disambiguate between a getter and a setter that have the
+ * same name.
+ */
+ static String SETTER_SUFFIX = "=";
+
+ /**
+ * The name used to look up the method used to implement the unary minus
+ * operator. Used to disambiguate between the unary and binary operators.
+ */
+ static String UNARY_MINUS = "unary-";
+
+ /**
+ * A table mapping names that are defined in this scope to the element
+ * representing the thing declared with that name.
+ */
+ HashMap<String, Element> _definedNames = null;
+
+ /**
+ * Return the scope in which this scope is lexically enclosed.
+ */
+ Scope get enclosingScope => null;
+
+ /**
+ * Return the listener that is to be informed when an error is encountered.
+ */
+ AnalysisErrorListener get errorListener;
+
+ /**
+ * Add the given [element] to this scope. If there is already an element with
+ * the given name defined in this scope, then an error will be generated and
+ * the original element will continue to be mapped to the name. If there is an
+ * element with the given name in an enclosing scope, then a warning will be
+ * generated but the given element will hide the inherited element.
+ */
+ void define(Element element) {
+ String name = _getName(element);
+ if (name != null && !name.isEmpty) {
+ if (_definedNames != null && _definedNames.containsKey(name)) {
+ errorListener
+ .onError(getErrorForDuplicate(_definedNames[name], element));
+ } else {
+ _definedNames ??= new HashMap<String, Element>();
+ _definedNames[name] = element;
+ }
+ }
+ }
+
+ /**
+ * Add the given [element] to this scope without checking for duplication or
+ * hiding.
+ */
+ void defineNameWithoutChecking(String name, Element element) {
+ _definedNames ??= new HashMap<String, Element>();
+ _definedNames[name] = element;
+ }
+
+ /**
+ * Add the given [element] to this scope without checking for duplication or
+ * hiding.
+ */
+ void defineWithoutChecking(Element element) {
+ _definedNames ??= new HashMap<String, Element>();
+ _definedNames[_getName(element)] = element;
+ }
+
+ /**
+ * Return the error code to be used when reporting that a name being defined
+ * locally conflicts with another element of the same name in the local scope.
+ * [existing] is the first element to be declared with the conflicting name,
+ * while [duplicate] another element declared with the conflicting name.
+ */
+ AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
+ // TODO(brianwilkerson) Customize the error message based on the types of
+ // elements that share the same name.
+ // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being
+ // generated.
+ Source source = duplicate.source;
+ return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength,
+ CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]);
+ }
+
+ /**
+ * Return the source that contains the given [identifier], or the source
+ * associated with this scope if the source containing the identifier could
+ * not be determined.
+ */
+ Source getSource(AstNode identifier) {
+ CompilationUnit unit =
+ identifier.getAncestor((node) => node is CompilationUnit);
+ if (unit != null) {
+ CompilationUnitElement unitElement = unit.element;
+ if (unitElement != null) {
+ return unitElement.source;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the element with which the given [name] is associated, or `null` if
+ * the name is not defined within this scope. The [identifier] is the
+ * identifier node to lookup element for, used to report correct kind of a
+ * problem and associate problem with. The [referencingLibrary] is the library
+ * that contains the reference to the name, used to implement library-level
+ * privacy.
+ */
+ Element internalLookup(
+ Identifier identifier, String name, LibraryElement referencingLibrary);
+
+ /**
+ * Return the element with which the given [name] is associated, or `null` if
+ * the name is not defined within this scope. This method only returns
+ * elements that are directly defined within this scope, not elements that are
+ * defined in an enclosing scope. The [referencingLibrary] is the library that
+ * contains the reference to the name, used to implement library-level privacy.
+ */
+ Element localLookup(String name, LibraryElement referencingLibrary) {
+ if (_definedNames != null) {
+ return _definedNames[name];
+ }
+ return null;
+ }
+
+ /**
+ * Return the element with which the given [identifier] is associated, or
+ * `null` if the name is not defined within this scope. The
+ * [referencingLibrary] is the library that contains the reference to the
+ * name, used to implement library-level privacy.
+ */
+ Element lookup(Identifier identifier, LibraryElement referencingLibrary) =>
+ internalLookup(identifier, identifier.name, referencingLibrary);
+
+ /**
+ * Return the name that will be used to look up the given [element].
+ */
+ String _getName(Element element) {
+ if (element is MethodElement) {
+ MethodElement method = element;
+ if (method.name == "-" && method.parameters.length == 0) {
+ return UNARY_MINUS;
+ }
+ }
+ return element.name;
+ }
+
+ /**
+ * Return `true` if the given [name] is a library-private name.
+ */
+ static bool isPrivateName(String name) =>
+ name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX);
+}
+
+/**
+ * The scope defined by the type parameters in a class.
+ */
+class TypeParameterScope extends EnclosedScope {
+ /**
+ * Initialize a newly created scope, enclosed within the [enclosingScope],
+ * that defined the type parameters from the given [classElement].
+ */
+ TypeParameterScope(Scope enclosingScope, ClassElement classElement)
+ : super(enclosingScope) {
+ if (classElement == null) {
+ throw new IllegalArgumentException("class element cannot be null");
+ }
+ _defineTypeParameters(classElement);
+ }
+
+ /**
+ * Define the type parameters declared by the [classElement].
+ */
+ void _defineTypeParameters(ClassElement classElement) {
+ for (TypeParameterElement typeParameter in classElement.typeParameters) {
+ define(typeParameter);
+ }
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 16113c5..b3a9e78 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -9,8 +9,7 @@
import 'package:analyzer/src/dart/constant/evaluation.dart';
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/engine.dart'
- show AnalysisEngine, RecordingErrorListener;
+import 'package:analyzer/src/generated/engine.dart' show RecordingErrorListener;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:analyzer/src/generated/source.dart' show Source;
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index e8591ae..b37ebea 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -219,14 +219,13 @@
Object visitCommentReference(CommentReference node) {
Identifier identifier = node.identifier;
if (identifier is SimpleIdentifier) {
- SimpleIdentifier simpleIdentifier = identifier;
- Element element = _resolveSimpleIdentifier(simpleIdentifier);
+ Element element = _resolveSimpleIdentifier(identifier);
if (element == null) {
//
// This might be a reference to an imported name that is missing the
// prefix.
//
- element = _findImportWithoutPrefix(simpleIdentifier);
+ element = _findImportWithoutPrefix(identifier);
if (element is MultiplyDefinedElement) {
// TODO(brianwilkerson) Report this error?
element = null;
@@ -242,14 +241,14 @@
if (element.library == null || element.library != _definingLibrary) {
// TODO(brianwilkerson) Report this error?
}
- simpleIdentifier.staticElement = element;
+ identifier.staticElement = element;
if (node.newKeyword != null) {
if (element is ClassElement) {
ConstructorElement constructor = element.unnamedConstructor;
if (constructor == null) {
// TODO(brianwilkerson) Report this error.
} else {
- simpleIdentifier.staticElement = constructor;
+ identifier.staticElement = constructor;
}
} else {
// TODO(brianwilkerson) Report this error.
@@ -257,9 +256,8 @@
}
}
} else if (identifier is PrefixedIdentifier) {
- PrefixedIdentifier prefixedIdentifier = identifier;
- SimpleIdentifier prefix = prefixedIdentifier.prefix;
- SimpleIdentifier name = prefixedIdentifier.identifier;
+ SimpleIdentifier prefix = identifier.prefix;
+ SimpleIdentifier name = identifier.identifier;
Element element = _resolveSimpleIdentifier(prefix);
if (element == null) {
// resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, prefix, prefix.getName());
@@ -291,7 +289,7 @@
}
}
if (memberElement == null) {
-// reportGetterOrSetterNotFound(prefixedIdentifier, name, element.getDisplayName());
+// reportGetterOrSetterNotFound(identifier, name, element.getDisplayName());
} else {
name.staticElement = memberElement;
}
@@ -321,18 +319,17 @@
super.visitConstructorDeclaration(node);
ConstructorElement element = node.element;
if (element is ConstructorElementImpl) {
- ConstructorElementImpl constructorElement = element;
ConstructorName redirectedNode = node.redirectedConstructor;
if (redirectedNode != null) {
// set redirected factory constructor
ConstructorElement redirectedElement = redirectedNode.staticElement;
- constructorElement.redirectedConstructor = redirectedElement;
+ element.redirectedConstructor = redirectedElement;
} else {
// set redirected generative constructor
for (ConstructorInitializer initializer in node.initializers) {
if (initializer is RedirectingConstructorInvocation) {
ConstructorElement redirectedElement = initializer.staticElement;
- constructorElement.redirectedConstructor = redirectedElement;
+ element.redirectedConstructor = redirectedElement;
}
}
}
@@ -354,8 +351,19 @@
Object visitConstructorName(ConstructorName node) {
DartType type = node.type.type;
if (type != null && type.isDynamic) {
- return null;
- } else if (type is! InterfaceType) {
+ // Nothing to do.
+ } else if (type is InterfaceType) {
+ // look up ConstructorElement
+ ConstructorElement constructor;
+ SimpleIdentifier name = node.name;
+ if (name == null) {
+ constructor = type.lookUpConstructor(null, _definingLibrary);
+ } else {
+ constructor = type.lookUpConstructor(name.name, _definingLibrary);
+ name.staticElement = constructor;
+ }
+ node.staticElement = constructor;
+ } else {
// TODO(brianwilkerson) Report these errors.
// ASTNode parent = node.getParent();
// if (parent instanceof InstanceCreationExpression) {
@@ -367,20 +375,7 @@
// } else {
// // This is part of a redirecting factory constructor; not sure which error code to use
// }
- return null;
}
- // look up ConstructorElement
- ConstructorElement constructor;
- SimpleIdentifier name = node.name;
- InterfaceType interfaceType = type as InterfaceType;
- if (name == null) {
- constructor = interfaceType.lookUpConstructor(null, _definingLibrary);
- } else {
- constructor =
- interfaceType.lookUpConstructor(name.name, _definingLibrary);
- name.staticElement = constructor;
- }
- node.staticElement = constructor;
return null;
}
@@ -722,8 +717,9 @@
} else {
DartType type = _getBestType(target);
if (type != null) {
- if (type.element is ClassElement) {
- classElementContext = type.element as ClassElement;
+ Element element = type.element;
+ if (element is ClassElement) {
+ classElementContext = element;
}
}
}
@@ -808,11 +804,14 @@
errorCode, StaticTypeWarningCode.UNDEFINED_SUPER_METHOD)) {
// Generate the type name.
// The error code will never be generated via type propagation
- DartType targetType = _getStaticType(target);
- if (targetType is InterfaceType && !targetType.isObject) {
- targetType = (targetType as InterfaceType).superclass;
+ DartType getSuperType(DartType type) {
+ if (type is InterfaceType && !type.isObject) {
+ return type.superclass;
+ }
+ return type;
}
- String targetTypeName = targetType == null ? null : targetType.name;
+ DartType targetType = getSuperType(_getStaticType(target));
+ String targetTypeName = targetType?.name;
_resolver.reportErrorForNode(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD,
methodName, [methodName.name, targetTypeName]);
}
@@ -887,20 +886,21 @@
if (identifier.inSetterContext()) {
_resolver.reportErrorForNode(StaticWarningCode.UNDEFINED_SETTER,
identifier, [identifier.name, prefixElement.name]);
- } else if (node.parent is Annotation) {
- Annotation annotation = node.parent as Annotation;
- _resolver.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
return null;
+ }
+ AstNode parent = node.parent;
+ if (parent is Annotation) {
+ _resolver.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION, parent);
} else {
_resolver.reportErrorForNode(StaticWarningCode.UNDEFINED_GETTER,
identifier, [identifier.name, prefixElement.name]);
}
return null;
}
- if (element is PropertyAccessorElement && identifier.inSetterContext()) {
- PropertyInducingElement variable =
- (element as PropertyAccessorElement).variable;
+ Element accessor = element;
+ if (accessor is PropertyAccessorElement && identifier.inSetterContext()) {
+ PropertyInducingElement variable = accessor.variable;
if (variable != null) {
PropertyAccessorElement setter = variable.setter;
if (setter != null) {
@@ -912,17 +912,16 @@
// the import that defines the prefix, not the prefix's element.
identifier.staticElement = element;
// Validate annotation element.
- if (node.parent is Annotation) {
- Annotation annotation = node.parent as Annotation;
- _resolveAnnotationElement(annotation);
- return null;
+ AstNode parent = node.parent;
+ if (parent is Annotation) {
+ _resolveAnnotationElement(parent);
}
return null;
}
// May be annotation, resolve invocation of "const" constructor.
- if (node.parent is Annotation) {
- Annotation annotation = node.parent as Annotation;
- _resolveAnnotationElement(annotation);
+ AstNode parent = node.parent;
+ if (parent is Annotation) {
+ _resolveAnnotationElement(parent);
}
//
// Otherwise, the prefix is really an expression that happens to be a simple
@@ -1083,18 +1082,19 @@
if (_isConstructorReturnType(node)) {
_resolver.reportErrorForNode(
CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node);
- } else if (node.parent is Annotation) {
- Annotation annotation = node.parent as Annotation;
- _resolver.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
- } else if (element is PrefixElement) {
- _resolver.reportErrorForNode(
- CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
- node,
- [element.name]);
} else {
- _recordUndefinedNode(_resolver.enclosingClass,
- StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
+ if (parent is Annotation) {
+ _resolver.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION, parent);
+ } else if (element != null) {
+ _resolver.reportErrorForNode(
+ CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
+ node,
+ [element.name]);
+ } else {
+ _recordUndefinedNode(_resolver.enclosingClass,
+ StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
+ }
}
}
node.staticElement = element;
@@ -1109,9 +1109,8 @@
//
// Validate annotation element.
//
- if (node.parent is Annotation) {
- Annotation annotation = node.parent as Annotation;
- _resolveAnnotationElement(annotation);
+ if (parent is Annotation) {
+ _resolveAnnotationElement(parent);
}
return null;
}
@@ -1200,8 +1199,7 @@
// Prefix is not declared, instead "prefix.id" are declared.
if (element is PrefixElement) {
return CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT;
- }
- if (element is PropertyAccessorElement) {
+ } else if (element is PropertyAccessorElement) {
//
// This is really a function expression invocation.
//
@@ -1415,12 +1413,11 @@
}
/**
- * Assuming that the given [expression] is a prefix for a deferred import,
+ * Assuming that the given [identifier] is a prefix for a deferred import,
* return the library that is being imported.
*/
- LibraryElement _getImportedLibrary(Expression expression) {
- PrefixElement prefixElement =
- (expression as SimpleIdentifier).staticElement as PrefixElement;
+ LibraryElement _getImportedLibrary(SimpleIdentifier identifier) {
+ PrefixElement prefixElement = identifier.staticElement as PrefixElement;
List<ImportElement> imports =
prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
return imports[0].importedLibrary;
@@ -1515,24 +1512,23 @@
DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
// TODO(jmesserly): support generic "call" methods on InterfaceType.
if (invokeType is FunctionType) {
- FunctionType type = invokeType;
- List<TypeParameterElement> parameters = type.typeFormals;
+ List<TypeParameterElement> parameters = invokeType.typeFormals;
NodeList<TypeName> arguments = typeArguments?.arguments;
if (arguments != null && arguments.length != parameters.length) {
_resolver.reportErrorForNode(
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
node,
- [type, parameters.length, arguments?.length ?? 0]);
+ [invokeType, parameters.length, arguments?.length ?? 0]);
// Wrong number of type arguments. Ignore them.
arguments = null;
}
if (parameters.isNotEmpty) {
if (arguments == null) {
- invokeType = _resolver.typeSystem.instantiateToBounds(type);
+ return _resolver.typeSystem.instantiateToBounds(invokeType);
} else {
- invokeType = type.instantiate(arguments.map((n) => n.type).toList());
+ return invokeType.instantiate(arguments.map((n) => n.type).toList());
}
}
}
@@ -1543,20 +1539,18 @@
* Return `true` if the given [expression] is a prefix for a deferred import.
*/
bool _isDeferredPrefix(Expression expression) {
- if (expression is! SimpleIdentifier) {
- return false;
+ if (expression is SimpleIdentifier) {
+ Element element = expression.staticElement;
+ if (element is PrefixElement) {
+ List<ImportElement> imports =
+ element.enclosingElement.getImportsWithPrefix(element);
+ if (imports.length != 1) {
+ return false;
+ }
+ return imports[0].isDeferred;
+ }
}
- Element element = (expression as SimpleIdentifier).staticElement;
- if (element is! PrefixElement) {
- return false;
- }
- PrefixElement prefixElement = element as PrefixElement;
- List<ImportElement> imports =
- prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
- if (imports.length != 1) {
- return false;
- }
- return imports[0].isDeferred;
+ return false;
}
/**
@@ -1869,9 +1863,8 @@
{
Identifier annName = annotation.name;
if (annName is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = annName;
- nameNode1 = prefixed.prefix;
- nameNode2 = prefixed.identifier;
+ nameNode1 = annName.prefix;
+ nameNode2 = annName.identifier;
} else {
nameNode1 = annName as SimpleIdentifier;
nameNode2 = null;
@@ -1891,8 +1884,7 @@
}
// Class(args)
if (element1 is ClassElement) {
- ClassElement classElement = element1;
- constructor = new InterfaceTypeImpl(classElement)
+ constructor = new InterfaceTypeImpl(element1)
.lookUpConstructor(null, _definingLibrary);
}
}
@@ -1904,8 +1896,7 @@
Element element2 = nameNode2.staticElement;
// Class.CONST - not resolved yet
if (element1 is ClassElement) {
- ClassElement classElement = element1;
- element2 = classElement.lookUpGetter(nameNode2.name, _definingLibrary);
+ element2 = element1.lookUpGetter(nameNode2.name, _definingLibrary);
}
// prefix.CONST or Class.CONST
if (element2 is PropertyAccessorElement) {
@@ -1920,8 +1911,7 @@
}
// Class.constructor(args)
if (element1 is ClassElement) {
- ClassElement classElement = element1;
- constructor = new InterfaceTypeImpl(classElement)
+ constructor = new InterfaceTypeImpl(element1)
.lookUpConstructor(nameNode2.name, _definingLibrary);
nameNode2.staticElement = constructor;
}
@@ -1933,11 +1923,10 @@
Element element2 = nameNode2.staticElement;
// element2 should be ClassElement
if (element2 is ClassElement) {
- ClassElement classElement = element2;
String name3 = nameNode3.name;
// prefix.Class.CONST
PropertyAccessorElement getter =
- classElement.lookUpGetter(name3, _definingLibrary);
+ element2.lookUpGetter(name3, _definingLibrary);
if (getter != null) {
nameNode3.staticElement = getter;
annotation.element = element2;
@@ -1945,7 +1934,7 @@
return;
}
// prefix.Class.constructor(args)
- constructor = new InterfaceTypeImpl(classElement)
+ constructor = new InterfaceTypeImpl(element2)
.lookUpConstructor(name3, _definingLibrary);
nameNode3.staticElement = constructor;
}
@@ -2084,17 +2073,15 @@
}
for (SimpleIdentifier name in names) {
String nameStr = name.name;
- Element element = namespace.get(nameStr);
- if (element == null) {
- element = namespace.get("$nameStr=");
- }
+ Element element = namespace.get(nameStr) ?? namespace.get("$nameStr=");
if (element != null) {
// Ensure that the name always resolves to a top-level variable
// rather than a getter or setter
if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
+ name.staticElement = element.variable;
+ } else {
+ name.staticElement = element;
}
- name.staticElement = element;
}
}
}
@@ -2298,8 +2285,7 @@
if (propertyName.inGetterContext()) {
if (!isStaticProperty &&
staticOrPropagatedEnclosingElt is ClassElement) {
- ClassElement classElement = staticOrPropagatedEnclosingElt;
- InterfaceType targetType = classElement.type;
+ InterfaceType targetType = staticOrPropagatedEnclosingElt.type;
if (!_enableStrictCallChecks &&
targetType != null &&
targetType.isDartCoreFunction &&
@@ -2308,7 +2294,8 @@
// invoked?
// resolveArgumentsToParameters(node.getArgumentList(), invokedFunction);
return;
- } else if (classElement.isEnum && propertyName.name == "_name") {
+ } else if (staticOrPropagatedEnclosingElt.isEnum &&
+ propertyName.name == "_name") {
_resolver.reportErrorForNode(
CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD,
propertyName,
@@ -2458,16 +2445,16 @@
*/
static void resolveMetadata(AnnotatedNode node) {
_resolveAnnotations(node.metadata);
- if (node is VariableDeclaration && node.parent is VariableDeclarationList) {
- VariableDeclarationList list = node.parent as VariableDeclarationList;
- _resolveAnnotations(list.metadata);
- if (list.parent is FieldDeclaration) {
- FieldDeclaration fieldDeclaration = list.parent as FieldDeclaration;
- _resolveAnnotations(fieldDeclaration.metadata);
- } else if (list.parent is TopLevelVariableDeclaration) {
- TopLevelVariableDeclaration variableDeclaration =
- list.parent as TopLevelVariableDeclaration;
- _resolveAnnotations(variableDeclaration.metadata);
+ if (node is VariableDeclaration) {
+ AstNode parent = node.parent;
+ if (parent is VariableDeclarationList) {
+ _resolveAnnotations(parent.metadata);
+ AstNode grandParent = parent.parent;
+ if (grandParent is FieldDeclaration) {
+ _resolveAnnotations(grandParent.metadata);
+ } else if (grandParent is TopLevelVariableDeclaration) {
+ _resolveAnnotations(grandParent.metadata);
+ }
}
}
}
@@ -2491,9 +2478,8 @@
static bool _isFactoryConstructorReturnType(SimpleIdentifier identifier) {
AstNode parent = identifier.parent;
if (parent is ConstructorDeclaration) {
- ConstructorDeclaration constructor = parent;
- return identical(constructor.returnType, identifier) &&
- constructor.factoryKeyword != null;
+ return identical(parent.returnType, identifier) &&
+ parent.factoryKeyword != null;
}
return false;
}
@@ -2505,14 +2491,11 @@
for (AstNode node = expression; node != null; node = node.parent) {
if (node is CompilationUnit) {
return false;
- }
- if (node is ConstructorDeclaration) {
+ } else if (node is ConstructorDeclaration) {
return node.factoryKeyword == null;
- }
- if (node is ConstructorFieldInitializer) {
+ } else if (node is ConstructorFieldInitializer) {
return false;
- }
- if (node is MethodDeclaration) {
+ } else if (node is MethodDeclaration) {
return !node.isStatic;
}
}
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index f3947b4..96cdd80 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -13,7 +13,6 @@
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart' show ScannerErrorCode;
-import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/generated/shared_messages.dart'
as shared_messages;
import 'package:analyzer/src/generated/java_core.dart';
@@ -144,34 +143,33 @@
String get message => _message;
@override
- bool operator ==(Object obj) {
- if (identical(obj, this)) {
+ bool operator ==(Object other) {
+ if (identical(other, this)) {
return true;
}
// prepare other AnalysisError
- if (obj is! AnalysisError) {
- return false;
+ if (other is AnalysisError) {
+ // Quick checks.
+ if (!identical(errorCode, other.errorCode)) {
+ return false;
+ }
+ if (offset != other.offset || length != other.length) {
+ return false;
+ }
+ if (isStaticOnly != other.isStaticOnly) {
+ return false;
+ }
+ // Deep checks.
+ if (_message != other._message) {
+ return false;
+ }
+ if (source != other.source) {
+ return false;
+ }
+ // OK
+ return true;
}
- AnalysisError other = obj as AnalysisError;
- // Quick checks.
- if (!identical(errorCode, other.errorCode)) {
- return false;
- }
- if (offset != other.offset || length != other.length) {
- return false;
- }
- if (isStaticOnly != other.isStaticOnly) {
- return false;
- }
- // Deep checks.
- if (_message != other._message) {
- return false;
- }
- if (source != other.source) {
- return false;
- }
- // OK
- return true;
+ return false;
}
/**
@@ -2686,6 +2684,7 @@
HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
HintCode.MISSING_JS_LIB_ANNOTATION,
HintCode.MISSING_REQUIRED_PARAM,
+ HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
HintCode.MISSING_RETURN,
HintCode.NULL_AWARE_IN_CONDITION,
HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER,
@@ -2695,9 +2694,11 @@
HintCode.TYPE_CHECK_IS_NOT_NULL,
HintCode.TYPE_CHECK_IS_NULL,
HintCode.UNDEFINED_GETTER,
+ HintCode.UNDEFINED_HIDDEN_NAME,
HintCode.UNDEFINED_METHOD,
HintCode.UNDEFINED_OPERATOR,
HintCode.UNDEFINED_SETTER,
+ HintCode.UNDEFINED_SHOWN_NAME,
HintCode.UNNECESSARY_CAST,
HintCode.UNNECESSARY_NO_SUCH_METHOD,
HintCode.UNNECESSARY_TYPE_CHECK_FALSE,
@@ -3265,12 +3266,12 @@
for (int i = 0; i < count; i++) {
Object argument = arguments[i];
if (argument is DartType) {
- DartType type = argument;
- Element element = type.element;
+ Element element = argument.element;
if (element == null) {
- arguments[i] = displayName(type);
+ arguments[i] = displayName(argument);
} else {
- arguments[i] = element.getExtendedDisplayName(displayName(type));
+ arguments[i] =
+ element.getExtendedDisplayName(displayName(argument));
}
}
}
@@ -3293,8 +3294,8 @@
int count = arguments.length;
HashSet<String> typeNames = new HashSet<String>();
for (int i = 0; i < count; i++) {
- if (arguments[i] is DartType &&
- !typeNames.add((arguments[i] as DartType).displayName)) {
+ Object argument = arguments[i];
+ if (argument is DartType && !typeNames.add(argument.displayName)) {
return true;
}
}
@@ -3581,12 +3582,22 @@
*
* Parameters:
* 0: the name of the parameter
- * 1: an optional reason
*/
static const HintCode MISSING_REQUIRED_PARAM = const HintCode(
+ 'MISSING_REQUIRED_PARAM', "The parameter '{0}' is required.");
+
+ /**
+ * Generate a hint for a constructor, function or method invocation where a
+ * required parameter is missing.
+ *
+ * Parameters:
+ * 0: the name of the parameter
+ * 1: message details
+ */
+ static const HintCode MISSING_REQUIRED_PARAM_WITH_DETAILS = const HintCode(
'MISSING_REQUIRED_PARAM', "The parameter '{0}' is required. {1}");
- /**
+ /**
* Generate a hint for an element that is annotated with `@JS(...)` whose
* library declaration is not similarly annotated.
*/
@@ -3687,6 +3698,13 @@
shared_messages.UNDEFINED_GETTER_HINT;
/**
+ * An undefined name hidden in an import or export directive.
+ */
+ static const HintCode UNDEFINED_HIDDEN_NAME = const HintCode(
+ 'UNDEFINED_HIDDEN_NAME',
+ "The library '{0}' doesn't export a member with the hidden name '{1}'");
+
+ /**
* This hint is generated anywhere where the
* [StaticTypeWarningCode.UNDEFINED_METHOD] would have been generated, if we
* used propagated information for the warnings.
@@ -3724,6 +3742,13 @@
shared_messages.UNDEFINED_SETTER_HINT;
/**
+ * An undefined name shown in an import or export directive.
+ */
+ static const HintCode UNDEFINED_SHOWN_NAME = const HintCode(
+ 'UNDEFINED_SHOWN_NAME',
+ "The library '{0}' doesn't export a member with the shown name '{1}'");
+
+ /**
* Unnecessary cast.
*/
static const HintCode UNNECESSARY_CAST =
@@ -3791,8 +3816,8 @@
/**
* Unused shown names are names shown on imports which are never used.
*/
- static const HintCode UNUSED_SHOWN_NAME =
- const HintCode('UNUSED_SHOWN_NAME', "The name {0} is shown, but not used.");
+ static const HintCode UNUSED_SHOWN_NAME = const HintCode(
+ 'UNUSED_SHOWN_NAME', "The name {0} is shown, but not used.");
/**
* Hint for cases where the source expects a method or function to return a
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index ac7214d..c99057a 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -13,20 +13,21 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/parser.dart'
- show Parser, ParserErrorCode;
+import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary;
import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/task/strong/info.dart' show StaticInfo;
/**
* A visitor used to traverse an AST structure looking for additional errors and
@@ -72,6 +73,11 @@
InterfaceType _intType;
/**
+ * The options for verification.
+ */
+ AnalysisOptions _options;
+
+ /**
* The object providing access to the types defined by the language.
*/
final TypeProvider _typeProvider;
@@ -301,6 +307,7 @@
_intType = _typeProvider.intType;
_DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT = _typeProvider.nonSubtypableTypes;
_typeSystem = _currentLibrary.context.typeSystem;
+ _options = _currentLibrary.context.analysisOptions;
}
@override
@@ -574,7 +581,9 @@
SimpleIdentifier fieldName = node.fieldName;
Element staticElement = fieldName.staticElement;
_checkForInvalidField(node, fieldName, staticElement);
- _checkForFieldInitializerNotAssignable(node, staticElement);
+ if (staticElement is FieldElement) {
+ _checkForFieldInitializerNotAssignable(node, staticElement);
+ }
return super.visitConstructorFieldInitializer(node);
} finally {
_isInConstructorInitializer = false;
@@ -644,10 +653,10 @@
DartType expectedReturnType = functionType == null
? DynamicTypeImpl.instance
: functionType.returnType;
- bool isSetterWithImplicitReturn =
- _enclosingFunction.hasImplicitReturnType &&
- _enclosingFunction is PropertyAccessorElement &&
- (_enclosingFunction as PropertyAccessorElement).isSetter;
+ ExecutableElement function = _enclosingFunction;
+ bool isSetterWithImplicitReturn = function.hasImplicitReturnType &&
+ function is PropertyAccessorElement &&
+ function.isSetter;
if (!isSetterWithImplicitReturn) {
_checkForReturnOfInvalidType(node.expression, expectedReturnType);
}
@@ -817,9 +826,8 @@
TypeName typeName = constructorName.type;
DartType type = typeName.type;
if (type is InterfaceType) {
- InterfaceType interfaceType = type;
- _checkForConstOrNewWithAbstractClass(node, typeName, interfaceType);
- _checkForConstOrNewWithEnum(node, typeName, interfaceType);
+ _checkForConstOrNewWithAbstractClass(node, typeName, type);
+ _checkForConstOrNewWithEnum(node, typeName, type);
_checkForMissingRequiredParam(
node.staticElement?.type, node.argumentList, node.constructorName);
if (_isInConstInstanceCreation) {
@@ -1236,10 +1244,13 @@
NodeList<FormalParameter> formalParameters =
constructor.parameters.parameters;
for (FormalParameter formalParameter in formalParameters) {
- FormalParameter parameter = formalParameter;
- if (parameter is DefaultFormalParameter) {
- parameter = (parameter as DefaultFormalParameter).parameter;
+ FormalParameter baseParameter(FormalParameter parameter) {
+ if (parameter is DefaultFormalParameter) {
+ return parameter.parameter;
+ }
+ return parameter;
}
+ FormalParameter parameter = baseParameter(formalParameter);
if (parameter is FieldFormalParameter) {
FieldElement fieldElement =
(parameter.element as FieldFormalParameterElementImpl).field;
@@ -1271,17 +1282,14 @@
return;
}
if (constructorInitializer is ConstructorFieldInitializer) {
- ConstructorFieldInitializer constructorFieldInitializer =
- constructorInitializer;
- SimpleIdentifier fieldName = constructorFieldInitializer.fieldName;
+ SimpleIdentifier fieldName = constructorInitializer.fieldName;
Element element = fieldName.staticElement;
if (element is FieldElement) {
- FieldElement fieldElement = element;
- INIT_STATE state = fieldElementsMap[fieldElement];
+ INIT_STATE state = fieldElementsMap[element];
if (state == INIT_STATE.NOT_INIT) {
- fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_INITIALIZERS;
+ fieldElementsMap[element] = INIT_STATE.INIT_IN_INITIALIZERS;
} else if (state == INIT_STATE.INIT_IN_DECLARATION) {
- if (fieldElement.isFinal || fieldElement.isConst) {
+ if (element.isFinal || element.isConst) {
_errorReporter.reportErrorForNode(
StaticWarningCode
.FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION,
@@ -1296,7 +1304,7 @@
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS,
fieldName,
- [fieldElement.displayName]);
+ [element.displayName]);
}
}
}
@@ -1376,9 +1384,8 @@
bool isGetter = false;
bool isSetter = false;
if (executableElement is PropertyAccessorElement) {
- PropertyAccessorElement accessorElement = executableElement;
- isGetter = accessorElement.isGetter;
- isSetter = accessorElement.isSetter;
+ isGetter = executableElement.isGetter;
+ isSetter = executableElement.isSetter;
}
String executableElementName = executableElement.name;
FunctionType overridingFT = executableElement.type;
@@ -1807,27 +1814,26 @@
bool problemReported = false;
for (TypeName mixinName in withClause.mixinTypes) {
DartType mixinType = mixinName.type;
- if (mixinType is! InterfaceType) {
- continue;
- }
- if (_checkForExtendsOrImplementsDisallowedClass(
- mixinName, CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS)) {
- problemReported = true;
- } else {
- ClassElement mixinElement = (mixinType as InterfaceType).element;
- if (_checkForExtendsOrImplementsDeferredClass(
- mixinName, CompileTimeErrorCode.MIXIN_DEFERRED_CLASS)) {
+ if (mixinType is InterfaceType) {
+ if (_checkForExtendsOrImplementsDisallowedClass(
+ mixinName, CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS)) {
problemReported = true;
- }
- if (_checkForMixinDeclaresConstructor(mixinName, mixinElement)) {
- problemReported = true;
- }
- if (!enableSuperMixins &&
- _checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
- problemReported = true;
- }
- if (_checkForMixinReferencesSuper(mixinName, mixinElement)) {
- problemReported = true;
+ } else {
+ ClassElement mixinElement = mixinType.element;
+ if (_checkForExtendsOrImplementsDeferredClass(
+ mixinName, CompileTimeErrorCode.MIXIN_DEFERRED_CLASS)) {
+ problemReported = true;
+ }
+ if (_checkForMixinDeclaresConstructor(mixinName, mixinElement)) {
+ problemReported = true;
+ }
+ if (!enableSuperMixins &&
+ _checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
+ problemReported = true;
+ }
+ if (_checkForMixinReferencesSuper(mixinName, mixinElement)) {
+ problemReported = true;
+ }
}
}
}
@@ -1917,9 +1923,9 @@
: functionType.returnType;
Expression returnExpression = statement.expression;
// RETURN_IN_GENERATIVE_CONSTRUCTOR
- bool isGenerativeConstructor = _enclosingFunction is ConstructorElement &&
- !(_enclosingFunction as ConstructorElement).isFactory;
- if (isGenerativeConstructor) {
+ bool isGenerativeConstructor(ExecutableElement element) =>
+ element is ConstructorElement && !element.isFactory;
+ if (isGenerativeConstructor(_enclosingFunction)) {
if (returnExpression == null) {
return;
}
@@ -2008,11 +2014,9 @@
DartType actualStaticType,
ErrorCode errorCode) {
// Warning case: test static type information
- if (actualStaticType != null &&
- expectedStaticType != null &&
- !_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) {
- _errorReporter.reportTypeErrorForNode(
- errorCode, expression, [actualStaticType, expectedStaticType]);
+ if (actualStaticType != null && expectedStaticType != null) {
+ _checkForAssignableExpressionAtType(
+ expression, actualStaticType, expectedStaticType, errorCode);
}
}
@@ -2092,12 +2096,36 @@
if (expressionType == null) {
return;
}
- if (_typeSystem.isAssignableTo(expressionType, type)) {
+ if (_expressionIsAssignableAtType(expression, expressionType, type)) {
return;
}
_errorReporter.reportErrorForNode(errorCode, expression, arguments);
}
+ bool _checkForAssignableExpression(
+ Expression expression, DartType expectedStaticType, ErrorCode errorCode) {
+ DartType actualStaticType = getStaticType(expression);
+ return actualStaticType != null &&
+ _checkForAssignableExpressionAtType(
+ expression, actualStaticType, expectedStaticType, errorCode);
+ }
+
+ bool _checkForAssignableExpressionAtType(
+ Expression expression,
+ DartType actualStaticType,
+ DartType expectedStaticType,
+ ErrorCode errorCode) {
+ // TODO(leafp): Move the Downcast functionality here.
+ // TODO(leafp): Support strict downcasts
+ if (!_expressionIsAssignableAtType(
+ expression, actualStaticType, expectedStaticType)) {
+ _errorReporter.reportTypeErrorForNode(
+ errorCode, expression, [actualStaticType, expectedStaticType]);
+ return false;
+ }
+ return true;
+ }
+
/**
* Verify that the given [expression] is not final.
*
@@ -2115,15 +2143,14 @@
highlightedNode = expression.identifier;
}
} else if (expression is PropertyAccess) {
- PropertyAccess propertyAccess = expression;
- element = propertyAccess.propertyName.staticElement;
- highlightedNode = propertyAccess.propertyName;
+ element = expression.propertyName.staticElement;
+ highlightedNode = expression.propertyName;
}
// check if element is assignable
- if (element is PropertyAccessorElement) {
- PropertyAccessorElement accessor = element as PropertyAccessorElement;
- element = accessor.variable;
+ Element toVariable(Element element) {
+ return element is PropertyAccessorElement ? element.variable : element;
}
+ element = toVariable(element);
if (element is VariableElement) {
if (element.isConst) {
_errorReporter.reportErrorForNode(
@@ -2184,8 +2211,7 @@
// fall-through without statements at all
AstNode parent = switchCase.parent;
if (parent is SwitchStatement) {
- SwitchStatement switchStatement = parent;
- NodeList<SwitchMember> members = switchStatement.members;
+ NodeList<SwitchMember> members = parent.members;
int index = members.indexOf(switchCase);
if (index != -1 && index < members.length - 1) {
return;
@@ -2454,21 +2480,20 @@
// this prevents multiple warnings for one issue.
HashMap<String, ClassMember> memberHashMap =
new HashMap<String, ClassMember>();
- for (ClassMember classMember in classMembers) {
- if (classMember is MethodDeclaration) {
- MethodDeclaration method = classMember;
- if (method.isStatic) {
+ for (ClassMember member in classMembers) {
+ if (member is MethodDeclaration) {
+ if (member.isStatic) {
continue;
}
// prepare name
- SimpleIdentifier name = method.name;
+ SimpleIdentifier name = member.name;
if (name == null) {
continue;
}
bool addThisMemberToTheMap = true;
- bool isGetter = method.isGetter;
- bool isSetter = method.isSetter;
- bool isOperator = method.isOperator;
+ bool isGetter = member.isGetter;
+ bool isSetter = member.isSetter;
+ bool isOperator = member.isOperator;
bool isMethod = !isGetter && !isSetter && !isOperator;
// Do lookups in the enclosing class (and the inherited member) if the
// member is a method or a setter for
@@ -2512,10 +2537,10 @@
}
// Finally, add this member into the HashMap.
if (addThisMemberToTheMap) {
- if (method.isSetter) {
- memberHashMap["${name.name}="] = method;
+ if (member.isSetter) {
+ memberHashMap["${name.name}="] = member;
} else {
- memberHashMap[name.name] = method;
+ memberHashMap[name.name] = member;
}
}
}
@@ -2667,14 +2692,13 @@
// try to find and check super constructor invocation
for (ConstructorInitializer initializer in constructor.initializers) {
if (initializer is SuperConstructorInvocation) {
- SuperConstructorInvocation superInvocation = initializer;
- ConstructorElement element = superInvocation.staticElement;
+ ConstructorElement element = initializer.staticElement;
if (element == null || element.isConst) {
return;
}
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER,
- superInvocation,
+ initializer,
[element.enclosingElement.displayName]);
return;
}
@@ -2784,7 +2808,7 @@
if (type.element.isAbstract) {
ConstructorElement element = expression.staticElement;
if (element != null && !element.isFactory) {
- if ((expression.keyword as KeywordToken).keyword == Keyword.CONST) {
+ if (expression.keyword.keyword == Keyword.CONST) {
_errorReporter.reportErrorForNode(
StaticWarningCode.CONST_WITH_ABSTRACT_CLASS, typeName);
} else {
@@ -2910,10 +2934,9 @@
void _checkForDefaultValueInFunctionTypeAlias(FunctionTypeAlias alias) {
FormalParameterList formalParameterList = alias.parameters;
NodeList<FormalParameter> parameters = formalParameterList.parameters;
- for (FormalParameter formalParameter in parameters) {
- if (formalParameter is DefaultFormalParameter) {
- DefaultFormalParameter defaultFormalParameter = formalParameter;
- if (defaultFormalParameter.defaultValue != null) {
+ for (FormalParameter parameter in parameters) {
+ if (parameter is DefaultFormalParameter) {
+ if (parameter.defaultValue != null) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, alias);
}
@@ -2958,19 +2981,16 @@
for (int i = 0; i < count; i++) {
Directive directive = directives[i];
if (directive is ImportDirective) {
- ImportDirective importDirective = directive;
- SimpleIdentifier prefix = importDirective.prefix;
+ SimpleIdentifier prefix = directive.prefix;
if (prefix != null) {
Element element = prefix.staticElement;
if (element is PrefixElement) {
- PrefixElement prefixElement = element;
- List<ImportDirective> elements =
- prefixToDirectivesMap[prefixElement];
+ List<ImportDirective> elements = prefixToDirectivesMap[element];
if (elements == null) {
elements = new List<ImportDirective>();
- prefixToDirectivesMap[prefixElement] = elements;
+ prefixToDirectivesMap[element] = elements;
}
- elements.add(importDirective);
+ elements.add(directive);
}
}
}
@@ -3259,19 +3279,14 @@
/**
* Verify that the given constructor field [initializer] has compatible field
- * and initializer expression types. The [staticElement] is the static element
+ * and initializer expression types. The [fieldElement] is the static element
* from the name in the [ConstructorFieldInitializer].
*
* See [CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE], and
* [StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE].
*/
void _checkForFieldInitializerNotAssignable(
- ConstructorFieldInitializer initializer, Element staticElement) {
- // prepare field element
- if (staticElement is! FieldElement) {
- return;
- }
- FieldElement fieldElement = staticElement as FieldElement;
+ ConstructorFieldInitializer initializer, FieldElement fieldElement) {
// prepare field type
DartType fieldType = fieldElement.type;
// prepare expression type
@@ -3284,7 +3299,7 @@
if (staticType == null) {
return;
}
- if (_typeSystem.isAssignableTo(staticType, fieldType)) {
+ if (_expressionIsAssignableAtType(expression, staticType, fieldType)) {
return;
}
// report problem
@@ -3425,14 +3440,27 @@
}
if (_enclosingFunction.isAsynchronous) {
if (_enclosingFunction.isGenerator) {
- if (!_typeSystem.isAssignableTo(
+ if (_options.strongMode) {
+ if (_enclosingFunction.returnType.element !=
+ _typeProvider.streamType.element) {
+ _errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE,
+ returnType);
+ }
+ } else if (!_typeSystem.isAssignableTo(
_enclosingFunction.returnType, _typeProvider.streamDynamicType)) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE,
returnType);
}
} else {
- if (!_typeSystem.isAssignableTo(
+ if (_options.strongMode) {
+ if (_enclosingFunction.returnType.element !=
+ _typeProvider.futureType.element) {
+ _errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE, returnType);
+ }
+ } else if (!_typeSystem.isAssignableTo(
_enclosingFunction.returnType, _typeProvider.futureDynamicType)) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE, returnType);
@@ -3523,23 +3551,20 @@
}
// qualified method invocation
if (parent is MethodInvocation) {
- MethodInvocation invocation = parent;
- if (identical(invocation.methodName, identifier) &&
- invocation.realTarget != null) {
+ if (identical(parent.methodName, identifier) &&
+ parent.realTarget != null) {
return;
}
}
// qualified property access
if (parent is PropertyAccess) {
- PropertyAccess access = parent;
- if (identical(access.propertyName, identifier) &&
- access.realTarget != null) {
+ if (identical(parent.propertyName, identifier) &&
+ parent.realTarget != null) {
return;
}
}
if (parent is PrefixedIdentifier) {
- PrefixedIdentifier prefixed = parent;
- if (identical(prefixed.identifier, identifier)) {
+ if (identical(parent.identifier, identifier)) {
return;
}
}
@@ -3626,9 +3651,8 @@
// Ensure that the inheritance manager has a chance to generate all errors
// we may care about, note that we ensure that the interfaces data since
// there are no errors.
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass);
- HashSet<AnalysisError> errors =
- _inheritanceManager.getErrors(_enclosingClass);
+ _inheritanceManager.getMembersInheritedFromInterfaces(_enclosingClass);
+ Set<AnalysisError> errors = _inheritanceManager.getErrors(_enclosingClass);
if (errors == null || errors.isEmpty) {
return;
}
@@ -3712,23 +3736,20 @@
}
// prepare member Element
Element element = name.staticElement;
- if (element is! ExecutableElement) {
- return;
+ if (element is ExecutableElement) {
+ // OK, top-level element
+ if (element.enclosingElement is! ClassElement) {
+ return;
+ }
+ // OK, instance member
+ if (!element.isStatic) {
+ return;
+ }
+ _errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
+ name,
+ [name.name]);
}
- ExecutableElement executableElement = element as ExecutableElement;
- // OK, top-level element
- if (executableElement.enclosingElement is! ClassElement) {
- return;
- }
- // OK, instance member
- if (!executableElement.isStatic) {
- return;
- }
-
- _errorReporter.reportErrorForNode(
- StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
- name,
- [name.name]);
}
/**
@@ -3852,13 +3873,8 @@
DartType leftType = (leftVariableElement == null)
? getStaticType(lhs)
: leftVariableElement.type;
- DartType staticRightType = getStaticType(rhs);
- if (!_typeSystem.isAssignableTo(staticRightType, leftType)) {
- _errorReporter.reportTypeErrorForNode(
- StaticTypeWarningCode.INVALID_ASSIGNMENT,
- rhs,
- [staticRightType, leftType]);
- }
+ _checkForAssignableExpression(
+ rhs, leftType, StaticTypeWarningCode.INVALID_ASSIGNMENT);
}
/**
@@ -3900,13 +3916,12 @@
void _checkForInvalidField(ConstructorFieldInitializer initializer,
SimpleIdentifier fieldName, Element staticElement) {
if (staticElement is FieldElement) {
- FieldElement fieldElement = staticElement;
- if (fieldElement.isSynthetic) {
+ if (staticElement.isSynthetic) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD,
initializer,
[fieldName]);
- } else if (fieldElement.isStatic) {
+ } else if (staticElement.isStatic) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD,
initializer,
@@ -4071,82 +4086,81 @@
Declaration accessorDeclaration, String accessorTextName) {
ExecutableElement accessorElement =
accessorDeclaration.element as ExecutableElement;
- if (accessorElement is! PropertyAccessorElement) {
- return;
- }
- PropertyAccessorElement propertyAccessorElement =
- accessorElement as PropertyAccessorElement;
- PropertyAccessorElement counterpartAccessor = null;
- ClassElement enclosingClassForCounterpart = null;
- if (propertyAccessorElement.isGetter) {
- counterpartAccessor = propertyAccessorElement.correspondingSetter;
- } else {
- counterpartAccessor = propertyAccessorElement.correspondingGetter;
- // If the setter and getter are in the same enclosing element, return,
- // this prevents having MISMATCHED_GETTER_AND_SETTER_TYPES reported twice.
- if (counterpartAccessor != null &&
- identical(counterpartAccessor.enclosingElement,
- propertyAccessorElement.enclosingElement)) {
- return;
- }
- }
- if (counterpartAccessor == null) {
- // If the accessor is declared in a class, check the superclasses.
- if (_enclosingClass != null) {
- // Figure out the correct identifier to lookup in the inheritance graph,
- // if 'x', then 'x=', or if 'x=', then 'x'.
- String lookupIdentifier = propertyAccessorElement.name;
- if (StringUtilities.endsWithChar(lookupIdentifier, 0x3D)) {
- lookupIdentifier =
- lookupIdentifier.substring(0, lookupIdentifier.length - 1);
- } else {
- lookupIdentifier += "=";
- }
- // lookup with the identifier.
- ExecutableElement elementFromInheritance = _inheritanceManager
- .lookupInheritance(_enclosingClass, lookupIdentifier);
- // Verify that we found something, and that it is an accessor
- if (elementFromInheritance != null &&
- elementFromInheritance is PropertyAccessorElement) {
- enclosingClassForCounterpart =
- elementFromInheritance.enclosingElement as ClassElement;
- counterpartAccessor = elementFromInheritance;
+ if (accessorElement is PropertyAccessorElement) {
+ PropertyAccessorElement counterpartAccessor = null;
+ ClassElement enclosingClassForCounterpart = null;
+ if (accessorElement.isGetter) {
+ counterpartAccessor = accessorElement.correspondingSetter;
+ } else {
+ counterpartAccessor = accessorElement.correspondingGetter;
+ // If the setter and getter are in the same enclosing element, return,
+ // this prevents having MISMATCHED_GETTER_AND_SETTER_TYPES reported twice.
+ if (counterpartAccessor != null &&
+ identical(counterpartAccessor.enclosingElement,
+ accessorElement.enclosingElement)) {
+ return;
}
}
if (counterpartAccessor == null) {
- return;
+ // If the accessor is declared in a class, check the superclasses.
+ if (_enclosingClass != null) {
+ // Figure out the correct identifier to lookup in the inheritance graph,
+ // if 'x', then 'x=', or if 'x=', then 'x'.
+ String lookupIdentifier = accessorElement.name;
+ if (StringUtilities.endsWithChar(lookupIdentifier, 0x3D)) {
+ lookupIdentifier =
+ lookupIdentifier.substring(0, lookupIdentifier.length - 1);
+ } else {
+ lookupIdentifier += "=";
+ }
+ // lookup with the identifier.
+ ExecutableElement elementFromInheritance = _inheritanceManager
+ .lookupInheritance(_enclosingClass, lookupIdentifier);
+ // Verify that we found something, and that it is an accessor
+ if (elementFromInheritance != null &&
+ elementFromInheritance is PropertyAccessorElement) {
+ enclosingClassForCounterpart =
+ elementFromInheritance.enclosingElement as ClassElement;
+ counterpartAccessor = elementFromInheritance;
+ }
+ }
+ if (counterpartAccessor == null) {
+ return;
+ }
}
- }
- // Default of null == no accessor or no type (dynamic)
- DartType getterType = null;
- DartType setterType = null;
- // Get an existing counterpart accessor if any.
- if (propertyAccessorElement.isGetter) {
- getterType = _getGetterType(propertyAccessorElement);
- setterType = _getSetterType(counterpartAccessor);
- } else if (propertyAccessorElement.isSetter) {
- setterType = _getSetterType(propertyAccessorElement);
- getterType = _getGetterType(counterpartAccessor);
- }
- // If either types are not assignable to each other, report an error
- // (if the getter is null, it is dynamic which is assignable to everything).
- if (setterType != null &&
- getterType != null &&
- !_typeSystem.isAssignableTo(getterType, setterType)) {
- if (enclosingClassForCounterpart == null) {
- _errorReporter.reportTypeErrorForNode(
- StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES,
- accessorDeclaration,
- [accessorTextName, setterType, getterType]);
- } else {
- _errorReporter.reportTypeErrorForNode(
- StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE,
- accessorDeclaration, [
- accessorTextName,
- setterType,
- getterType,
- enclosingClassForCounterpart.displayName
- ]);
+ // Default of null == no accessor or no type (dynamic)
+ DartType getterType = null;
+ DartType setterType = null;
+ // Get an existing counterpart accessor if any.
+ if (accessorElement.isGetter) {
+ getterType = _getGetterType(accessorElement);
+ setterType = _getSetterType(counterpartAccessor);
+ } else if (accessorElement.isSetter) {
+ setterType = _getSetterType(accessorElement);
+ getterType = _getGetterType(counterpartAccessor);
+ }
+ // If either types are not assignable to each other, report an error
+ // (if the getter is null, it is dynamic which is assignable to everything).
+ if (setterType != null &&
+ getterType != null &&
+ !_typeSystem.isAssignableTo(getterType, setterType)) {
+ if (enclosingClassForCounterpart == null) {
+ _errorReporter.reportTypeErrorForNode(
+ StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES,
+ accessorDeclaration,
+ [accessorTextName, setterType, getterType]);
+ } else {
+ _errorReporter.reportTypeErrorForNode(
+ StaticWarningCode
+ .MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE,
+ accessorDeclaration,
+ [
+ accessorTextName,
+ setterType,
+ getterType,
+ enclosingClassForCounterpart.displayName
+ ]);
+ }
}
}
}
@@ -4165,45 +4179,44 @@
return;
}
Element expressionElement = expressionType.element;
- if (expressionElement is! ClassElement) {
- return;
- }
- ClassElement classElement = expressionElement as ClassElement;
- if (!classElement.isEnum) {
- return;
- }
- List<String> constantNames = <String>[];
- List<FieldElement> fields = classElement.fields;
- int fieldCount = fields.length;
- for (int i = 0; i < fieldCount; i++) {
- FieldElement field = fields[i];
- if (field.isStatic && !field.isSynthetic) {
- constantNames.add(field.name);
- }
- }
- NodeList<SwitchMember> members = statement.members;
- int memberCount = members.length;
- for (int i = 0; i < memberCount; i++) {
- SwitchMember member = members[i];
- if (member is SwitchDefault) {
+ if (expressionElement is ClassElement) {
+ if (!expressionElement.isEnum) {
return;
}
- String constantName = _getConstantName((member as SwitchCase).expression);
- if (constantName != null) {
- constantNames.remove(constantName);
+ List<String> constantNames = <String>[];
+ List<FieldElement> fields = expressionElement.fields;
+ int fieldCount = fields.length;
+ for (int i = 0; i < fieldCount; i++) {
+ FieldElement field = fields[i];
+ if (field.isStatic && !field.isSynthetic) {
+ constantNames.add(field.name);
+ }
}
- }
- if (constantNames.isEmpty) {
- return;
- }
- for (int i = 0; i < constantNames.length; i++) {
- int offset = statement.offset;
- int end = statement.rightParenthesis.end;
- _errorReporter.reportErrorForOffset(
- StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
- offset,
- end - offset,
- [constantNames[i]]);
+ NodeList<SwitchMember> members = statement.members;
+ int memberCount = members.length;
+ for (int i = 0; i < memberCount; i++) {
+ SwitchMember member = members[i];
+ if (member is SwitchDefault) {
+ return;
+ }
+ String constantName =
+ _getConstantName((member as SwitchCase).expression);
+ if (constantName != null) {
+ constantNames.remove(constantName);
+ }
+ }
+ if (constantNames.isEmpty) {
+ return;
+ }
+ for (int i = 0; i < constantNames.length; i++) {
+ int offset = statement.offset;
+ int end = statement.rightParenthesis.end;
+ _errorReporter.reportErrorForOffset(
+ StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
+ offset,
+ end - offset,
+ [constantNames[i]]);
+ }
}
}
@@ -4228,10 +4241,16 @@
String paramName = param.name;
if (!_containsNamedExpression(argumentList, paramName)) {
DartObject constantValue = annotation.constantValue;
- String reason =
- constantValue.getField('reason')?.toStringValue() ?? '';
- _errorReporter.reportErrorForNode(
- HintCode.MISSING_REQUIRED_PARAM, node, [paramName, reason]);
+ String reason = constantValue.getField('reason')?.toStringValue();
+ if (reason != null) {
+ _errorReporter.reportErrorForNode(
+ HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
+ node,
+ [paramName, reason]);
+ } else {
+ _errorReporter.reportErrorForNode(
+ HintCode.MISSING_REQUIRED_PARAM, node, [paramName]);
+ }
}
}
}
@@ -4496,14 +4515,13 @@
// Loop through the set of all executable elements declared in the implicit
// interface.
//
- MemberMap membersInheritedFromInterfaces = _inheritanceManager
- .getMapOfMembersInheritedFromInterfaces(_enclosingClass);
- MemberMap membersInheritedFromSuperclasses = _inheritanceManager
- .getMapOfMembersInheritedFromClasses(_enclosingClass);
- for (int i = 0; i < membersInheritedFromInterfaces.size; i++) {
- String memberName = membersInheritedFromInterfaces.getKey(i);
+ Map<String, ExecutableElement> membersInheritedFromInterfaces =
+ _inheritanceManager.getMembersInheritedFromInterfaces(_enclosingClass);
+ Map<String, ExecutableElement> membersInheritedFromSuperclasses =
+ _inheritanceManager.getMembersInheritedFromClasses(_enclosingClass);
+ for (String memberName in membersInheritedFromInterfaces.keys) {
ExecutableElement executableElt =
- membersInheritedFromInterfaces.getValue(i);
+ membersInheritedFromInterfaces[memberName];
if (memberName == null) {
break;
}
@@ -4524,7 +4542,7 @@
}
// First check to see if this element was declared in the superclass
// chain, in which case there is already a concrete implementation.
- ExecutableElement elt = membersInheritedFromSuperclasses.get(memberName);
+ ExecutableElement elt = membersInheritedFromSuperclasses[memberName];
// Check to see if an element was found in the superclass chain with the
// correct name.
if (elt != null) {
@@ -4573,12 +4591,11 @@
List<String> stringMembersArrayListSet = new List<String>();
for (int i = 0; i < missingOverridesArray.length; i++) {
String newStrMember;
- Element enclosingElement = missingOverridesArray[i].enclosingElement;
+ ExecutableElement element = missingOverridesArray[i];
+ Element enclosingElement = element.enclosingElement;
String prefix = StringUtilities.EMPTY;
- if (missingOverridesArray[i] is PropertyAccessorElement) {
- PropertyAccessorElement propertyAccessorElement =
- missingOverridesArray[i] as PropertyAccessorElement;
- if (propertyAccessorElement.isGetter) {
+ if (element is PropertyAccessorElement) {
+ if (element.isGetter) {
prefix = _GETTER_SPACE;
// "getter "
} else {
@@ -4588,9 +4605,9 @@
}
if (enclosingElement != null) {
newStrMember =
- "$prefix'${enclosingElement.displayName}.${missingOverridesArray[i].displayName}'";
+ "$prefix'${enclosingElement.displayName}.${element.displayName}'";
} else {
- newStrMember = "$prefix'${missingOverridesArray[i].displayName}'";
+ newStrMember = "$prefix'${element.displayName}'";
}
stringMembersArrayListSet.add(newStrMember);
}
@@ -4672,9 +4689,8 @@
StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression);
}
} else if (type is FunctionType) {
- FunctionType functionType = type;
- if (functionType.typeArguments.length == 0 &&
- !_typeSystem.isAssignableTo(functionType.returnType, _boolType)) {
+ if (type.typeArguments.length == 0 &&
+ !_typeSystem.isAssignableTo(type.returnType, _boolType)) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression);
}
@@ -5060,7 +5076,8 @@
]);
return;
}
- if (_typeSystem.isAssignableTo(staticReturnType, expectedReturnType)) {
+ if (_expressionIsAssignableAtType(
+ returnExpression, staticReturnType, expectedReturnType)) {
return;
}
_errorReporter.reportTypeErrorForNode(
@@ -5102,17 +5119,16 @@
}
// prepare member Element
Element element = name.staticElement;
- if (element is! ExecutableElement) {
- return;
+ if (element is ExecutableElement) {
+ // OK, static
+ if (element.isStatic) {
+ return;
+ }
+ _errorReporter.reportErrorForNode(
+ StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
+ name,
+ [name.name]);
}
- ExecutableElement memberElement = element as ExecutableElement;
- // OK, static
- if (memberElement.isStatic) {
- return;
- }
-
- _errorReporter.reportErrorForNode(
- StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER, name, [name.name]);
}
/**
@@ -5138,8 +5154,9 @@
Expression caseExpression = switchCase.expression;
DartType caseType = getStaticType(caseExpression);
+
// check types
- if (!_typeSystem.isAssignableTo(expressionType, caseType)) {
+ if (!_expressionIsAssignableAtType(expression, expressionType, caseType)) {
_errorReporter.reportErrorForNode(
StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
expression,
@@ -5190,37 +5207,37 @@
}
// prepare ClassElement
Element element = type.element;
- if (element is! ClassElement) {
- return;
- }
- ClassElement classElement = element as ClassElement;
- // prepare type parameters
- List<DartType> typeParameters = classElement.type.typeArguments;
- List<TypeParameterElement> boundingElts = classElement.typeParameters;
- // iterate over each bounded type parameter and corresponding argument
- NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments;
- List<DartType> typeArguments = (type as InterfaceType).typeArguments;
- int loopThroughIndex =
- math.min(typeNameArgList.length, boundingElts.length);
+ if (element is ClassElement) {
+ // prepare type parameters
+ List<DartType> typeParameters = element.type.typeArguments;
+ List<TypeParameterElement> boundingElts = element.typeParameters;
+ // iterate over each bounded type parameter and corresponding argument
+ NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments;
+ List<DartType> typeArguments = (type as InterfaceType).typeArguments;
+ int loopThroughIndex =
+ math.min(typeNameArgList.length, boundingElts.length);
- for (int i = 0; i < loopThroughIndex; i++) {
- TypeName argTypeName = typeNameArgList[i];
- DartType argType = argTypeName.type;
- DartType boundType = boundingElts[i].bound;
- if (argType != null && boundType != null) {
- if (typeArguments.length != 0 &&
- typeArguments.length == typeParameters.length) {
- boundType = boundType.substitute2(typeArguments, typeParameters);
- }
- if (!_typeSystem.isSubtypeOf(argType, boundType)) {
- ErrorCode errorCode;
- if (_isInConstInstanceCreation) {
- errorCode = CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS;
- } else {
- errorCode = StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS;
+ for (int i = 0; i < loopThroughIndex; i++) {
+ TypeName argTypeName = typeNameArgList[i];
+ DartType argType = argTypeName.type;
+ DartType boundType = boundingElts[i].bound;
+ if (argType != null && boundType != null) {
+ if (typeArguments.length != 0 &&
+ typeArguments.length == typeParameters.length) {
+ boundType = boundType.substitute2(typeArguments, typeParameters);
}
- _errorReporter.reportTypeErrorForNode(
- errorCode, argTypeName, [argType, boundType]);
+ if (!_typeSystem.isSubtypeOf(argType, boundType)) {
+ ErrorCode errorCode;
+ if (_isInConstInstanceCreation) {
+ errorCode =
+ CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS;
+ } else {
+ errorCode =
+ StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS;
+ }
+ _errorReporter.reportTypeErrorForNode(
+ errorCode, argTypeName, [argType, boundType]);
+ }
}
}
}
@@ -5380,8 +5397,7 @@
} else {
ParameterElement parameterElement = parameter.element;
if (parameterElement is FieldFormalParameterElementImpl) {
- FieldFormalParameterElementImpl fieldFormal = parameterElement;
- DartType declaredType = fieldFormal.type;
+ DartType declaredType = parameterElement.type;
DartType fieldType = fieldElement.type;
if (fieldElement.isSynthetic) {
_errorReporter.reportErrorForNode(
@@ -5545,11 +5561,8 @@
impliedReturnType =
_typeProvider.iterableType.instantiate(<DartType>[staticYieldedType]);
}
- if (!_typeSystem.isAssignableTo(impliedReturnType, declaredReturnType)) {
- _errorReporter.reportTypeErrorForNode(
- StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
- yieldExpression,
- [impliedReturnType, declaredReturnType]);
+ if (!_checkForAssignableExpressionAtType(yieldExpression, impliedReturnType,
+ declaredReturnType, StaticTypeWarningCode.YIELD_OF_INVALID_TYPE)) {
return;
}
if (isYieldEach) {
@@ -5663,6 +5676,19 @@
return false;
}
+ bool _expressionIsAssignableAtType(Expression expression,
+ DartType actualStaticType, DartType expectedStaticType) {
+ bool concrete =
+ _options.strongMode && StaticInfo.isKnownFunction(expression);
+ if (concrete) {
+ actualStaticType =
+ _typeSystem.typeToConcreteType(_typeProvider, actualStaticType);
+ // TODO(leafp): Move the Downcast functionality here.
+ // TODO(leafp): Support strict downcasts
+ }
+ return _typeSystem.isAssignableTo(actualStaticType, expectedStaticType);
+ }
+
MethodElement _findOverriddenMemberThatMustCallSuper(MethodDeclaration node) {
ExecutableElement overriddenMember = _getOverriddenMember(node.element);
List<ExecutableElement> seen = <ExecutableElement>[];
@@ -5781,6 +5807,12 @@
* indirectly.
*/
bool _hasRedirectingFactoryConstructorCycle(ConstructorElement constructor) {
+ ConstructorElement nonMember(ConstructorElement constructor) {
+ return constructor is ConstructorMember
+ ? constructor.baseElement
+ : constructor;
+ }
+
Set<ConstructorElement> constructors = new HashSet<ConstructorElement>();
ConstructorElement current = constructor;
while (current != null) {
@@ -5788,10 +5820,7 @@
return identical(current, constructor);
}
constructors.add(current);
- current = current.redirectedConstructor;
- if (current is ConstructorMember) {
- current = (current as ConstructorMember).baseElement;
- }
+ current = nonMember(current.redirectedConstructor);
}
return false;
}
@@ -5866,22 +5895,21 @@
String executableName = executableElement.name;
if (executableElement is MethodElement) {
foundElt = classElement.getMethod(executableName);
- if (foundElt != null && !(foundElt as MethodElement).isAbstract) {
+ if (foundElt != null && !foundElt.isAbstract) {
return true;
}
List<InterfaceType> mixins = classElement.mixins;
for (int i = 0; i < mixins.length && foundElt == null; i++) {
foundElt = mixins[i].getMethod(executableName);
}
- if (foundElt != null && !(foundElt as MethodElement).isAbstract) {
+ if (foundElt != null && !foundElt.isAbstract) {
return true;
}
} else if (executableElement is PropertyAccessorElement) {
- PropertyAccessorElement propertyAccessorElement = executableElement;
- if (propertyAccessorElement.isGetter) {
+ if (executableElement.isGetter) {
foundElt = classElement.getGetter(executableName);
}
- if (foundElt == null && propertyAccessorElement.isSetter) {
+ if (foundElt == null && executableElement.isSetter) {
foundElt = classElement.getSetter(executableName);
}
if (foundElt != null &&
@@ -5895,8 +5923,7 @@
foundElt = mixins[i].getSetter(executableName);
}
}
- if (foundElt != null &&
- !(foundElt as PropertyAccessorElement).isAbstract) {
+ if (foundElt != null && !foundElt.isAbstract) {
return true;
}
}
@@ -5910,14 +5937,11 @@
for (AstNode node = expression.parent; node != null; node = node.parent) {
if (node is CompilationUnit) {
return false;
- }
- if (node is ConstructorDeclaration) {
+ } else if (node is ConstructorDeclaration) {
return node.factoryKeyword == null;
- }
- if (node is ConstructorInitializer) {
+ } else if (node is ConstructorInitializer) {
return false;
- }
- if (node is MethodDeclaration) {
+ } else if (node is MethodDeclaration) {
return !node.isStatic;
}
}
@@ -6101,8 +6125,7 @@
toCheck.add(type.element);
// type arguments
if (type is InterfaceType) {
- InterfaceType interfaceType = type;
- for (DartType typeArgument in interfaceType.typeArguments) {
+ for (DartType typeArgument in type.typeArguments) {
_addTypeToCheck(typeArgument);
}
}
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 9ed4477..2b98d4a 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -18,6 +18,7 @@
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/constant.dart';
@@ -422,8 +423,9 @@
(node.parent as VariableDeclarationList).type, element.type);
// matches, restore the existing element
node.name.staticElement = element;
- if (element is VariableElementImpl) {
- (element as VariableElementImpl).initializer = newElement.initializer;
+ Element variable = element;
+ if (variable is VariableElementImpl) {
+ variable.initializer = newElement.initializer;
}
}
@@ -1622,7 +1624,6 @@
RecordingErrorListener errorListener = new RecordingErrorListener();
Parser parser = new Parser(_unitSource, errorListener);
AnalysisOptions options = _unitElement.context.analysisOptions;
- parser.parseConditionalDirectives = options.enableConditionalDirectives;
parser.parseGenericMethods = options.enableGenericMethods;
CompilationUnit unit = parser.parseCompilationUnit(token);
_newParseErrors = errorListener.errors;
@@ -1686,9 +1687,9 @@
setElementDocumentationComment(parentElement, parent);
} else if (parentElement == null && parent is FieldDeclaration) {
for (VariableDeclaration field in parent.fields.variables) {
- if (field.element is ElementImpl) {
- setElementDocumentationComment(
- field.element as ElementImpl, parent);
+ Element fieldElement = field.element;
+ if (fieldElement is ElementImpl) {
+ setElementDocumentationComment(fieldElement, parent);
}
}
}
@@ -1866,7 +1867,7 @@
static Token _getBeginTokenNotComment(AstNode node) {
Token oldBeginToken = node.beginToken;
if (oldBeginToken is CommentToken) {
- oldBeginToken = (oldBeginToken as CommentToken).parent;
+ return oldBeginToken.parent;
}
return oldBeginToken;
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 32afd15..98a26e9 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -15,8 +15,7 @@
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/generated/engine.dart'
- show AnalysisEngine, AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/generated/shared_messages.dart'
as shared_messages;
@@ -1833,7 +1832,7 @@
ResolutionCopier.copyResolutionData(oldNode, newNode);
IncrementalAstCloner cloner =
new IncrementalAstCloner(oldNode, newNode, _tokenMap);
- return originalStructure.accept(cloner) as AstNode;
+ return originalStructure.accept(cloner);
}
/**
@@ -2169,12 +2168,6 @@
bool _inInitializer = false;
/**
- * A flag indicating whether the parser is to parse conditional directives
- * syntax.
- */
- bool parseConditionalDirectives = false;
-
- /**
* A flag indicating whether the parser is to parse generic method syntax.
*/
bool parseGenericMethods = false;
@@ -2217,6 +2210,12 @@
this._parseAsync = parseAsync;
}
+ @deprecated
+ bool get parseConditionalDirectives => true;
+
+ @deprecated
+ void set parseConditionalDirectives(bool value) {}
+
/**
* Set whether parser is to parse function bodies.
*/
@@ -2414,7 +2413,7 @@
return _parseOperator(
commentAndMetadata, modifiers.externalKeyword, returnType);
} else if (_matchesIdentifier() &&
- _peek().matchesAny([
+ _peek().matchesAny(const <TokenType>[
TokenType.OPEN_PAREN,
TokenType.OPEN_CURLY_BRACKET,
TokenType.FUNCTION,
@@ -2428,8 +2427,11 @@
// We have found an error of some kind. Try to recover.
//
if (_matchesIdentifier()) {
- if (_peek().matchesAny(
- [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
+ if (_peek().matchesAny(const <TokenType>[
+ TokenType.EQ,
+ TokenType.COMMA,
+ TokenType.SEMICOLON
+ ])) {
//
// We appear to have a variable declaration with a type of "void".
//
@@ -2587,8 +2589,11 @@
methodName,
typeParameters,
parameters);
- } else if (_peek()
- .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
+ } else if (_peek().matchesAny(const <TokenType>[
+ TokenType.EQ,
+ TokenType.COMMA,
+ TokenType.SEMICOLON
+ ])) {
if (modifiers.constKeyword == null &&
modifiers.finalKeyword == null &&
modifiers.varKeyword == null) {
@@ -3038,18 +3043,14 @@
// better.
//
List<FormalParameter> parameters = new List<FormalParameter>();
- List<FormalParameter> normalParameters = new List<FormalParameter>();
- List<FormalParameter> positionalParameters = new List<FormalParameter>();
- List<FormalParameter> namedParameters = new List<FormalParameter>();
- List<FormalParameter> currentParameters = normalParameters;
Token leftSquareBracket = null;
Token rightSquareBracket = null;
Token leftCurlyBracket = null;
Token rightCurlyBracket = null;
ParameterKind kind = ParameterKind.REQUIRED;
bool firstParameter = true;
- bool reportedMuliplePositionalGroups = false;
- bool reportedMulipleNamedGroups = false;
+ bool reportedMultiplePositionalGroups = false;
+ bool reportedMultipleNamedGroups = false;
bool reportedMixedGroups = false;
bool wasOptionalParameter = false;
Token initialToken = null;
@@ -3074,31 +3075,29 @@
//
if (_matches(TokenType.OPEN_SQUARE_BRACKET)) {
wasOptionalParameter = true;
- if (leftSquareBracket != null && !reportedMuliplePositionalGroups) {
+ if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
_reportErrorForCurrentToken(
ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
- reportedMuliplePositionalGroups = true;
+ reportedMultiplePositionalGroups = true;
}
if (leftCurlyBracket != null && !reportedMixedGroups) {
_reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
reportedMixedGroups = true;
}
leftSquareBracket = getAndAdvance();
- currentParameters = positionalParameters;
kind = ParameterKind.POSITIONAL;
} else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
wasOptionalParameter = true;
- if (leftCurlyBracket != null && !reportedMulipleNamedGroups) {
+ if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
_reportErrorForCurrentToken(
ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
- reportedMulipleNamedGroups = true;
+ reportedMultipleNamedGroups = true;
}
if (leftSquareBracket != null && !reportedMixedGroups) {
_reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
reportedMixedGroups = true;
}
leftCurlyBracket = getAndAdvance();
- currentParameters = namedParameters;
kind = ParameterKind.NAMED;
}
//
@@ -3106,7 +3105,6 @@
//
FormalParameter parameter = _parseFormalParameter(kind);
parameters.add(parameter);
- currentParameters.add(parameter);
if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
_reportErrorForNode(
ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
@@ -3118,7 +3116,6 @@
// mismatched delimiters.
if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
rightSquareBracket = getAndAdvance();
- currentParameters = normalParameters;
if (leftSquareBracket == null) {
if (leftCurlyBracket != null) {
_reportErrorForCurrentToken(
@@ -3134,7 +3131,6 @@
kind = ParameterKind.REQUIRED;
} else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
rightCurlyBracket = getAndAdvance();
- currentParameters = normalParameters;
if (leftCurlyBracket == null) {
if (leftSquareBracket != null) {
_reportErrorForCurrentToken(
@@ -3447,12 +3443,17 @@
* label* nonLabeledStatement
*/
Statement parseStatement2() {
- List<Label> labels = new List<Label>();
+ List<Label> labels = null;
while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
- labels.add(parseLabel(isDeclaration: true));
+ Label label = parseLabel(isDeclaration: true);
+ if (labels == null) {
+ labels = <Label>[label];
+ } else {
+ labels.add(label);
+ }
}
Statement statement = _parseNonLabeledStatement();
- if (labels.isEmpty) {
+ if (labels == null) {
return statement;
}
return new LabeledStatement(labels, statement);
@@ -4072,8 +4073,8 @@
if (afterParameters == null) {
return false;
}
- if (afterParameters
- .matchesAny([TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
+ if (afterParameters.matchesAny(
+ const <TokenType>[TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
return true;
}
String lexeme = afterParameters.lexeme;
@@ -4121,7 +4122,7 @@
if (_matchesKeyword(Keyword.CONST)) {
// Look to see whether we might be at the start of a list or map literal,
// otherwise this should be the start of a variable declaration.
- return !_peek().matchesAny([
+ return !_peek().matchesAny(const <TokenType>[
TokenType.LT,
TokenType.OPEN_CURLY_BRACKET,
TokenType.OPEN_SQUARE_BRACKET,
@@ -4258,11 +4259,8 @@
_tokenMatches(token.next, TokenType.COLON)) {
token = token.next.next;
}
- if (token.type == TokenType.KEYWORD) {
- Keyword keyword = (token as KeywordToken).keyword;
- return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
- }
- return false;
+ Keyword keyword = token.keyword;
+ return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
}
/**
@@ -4467,21 +4465,24 @@
while (_isLikelyArgumentList()) {
TypeArgumentList typeArguments = _parseOptionalTypeArguments();
ArgumentList argumentList = parseArgumentList();
- if (expression is SimpleIdentifier) {
- expression = new MethodInvocation(null, null,
- expression as SimpleIdentifier, typeArguments, argumentList);
- } else if (expression is PrefixedIdentifier) {
- PrefixedIdentifier identifier = expression as PrefixedIdentifier;
+ Expression currentExpression = expression;
+ if (currentExpression is SimpleIdentifier) {
expression = new MethodInvocation(
- identifier.prefix,
- identifier.period,
- identifier.identifier,
+ null, null, currentExpression, typeArguments, argumentList);
+ } else if (currentExpression is PrefixedIdentifier) {
+ expression = new MethodInvocation(
+ currentExpression.prefix,
+ currentExpression.period,
+ currentExpression.identifier,
typeArguments,
argumentList);
- } else if (expression is PropertyAccess) {
- PropertyAccess access = expression as PropertyAccess;
- expression = new MethodInvocation(access.target, access.operator,
- access.propertyName, typeArguments, argumentList);
+ } else if (currentExpression is PropertyAccess) {
+ expression = new MethodInvocation(
+ currentExpression.target,
+ currentExpression.operator,
+ currentExpression.propertyName,
+ typeArguments,
+ argumentList);
} else {
expression = new FunctionExpressionInvocation(
expression, typeArguments, argumentList);
@@ -4703,12 +4704,12 @@
progress = true;
while (_isLikelyArgumentList()) {
TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- if (expression is PropertyAccess) {
- PropertyAccess propertyAccess = expression as PropertyAccess;
+ Expression currentExpression = expression;
+ if (currentExpression is PropertyAccess) {
expression = new MethodInvocation(
- propertyAccess.target,
- propertyAccess.operator,
- propertyAccess.propertyName,
+ currentExpression.target,
+ currentExpression.operator,
+ currentExpression.propertyName,
typeArguments,
parseArgumentList());
} else {
@@ -4986,14 +4987,16 @@
*/
CommentAndMetadata _parseCommentAndMetadata() {
Comment comment = _parseDocumentationComment();
- List<Annotation> metadata = new List<Annotation>();
+ List<Annotation> metadata = null;
while (_matches(TokenType.AT)) {
+ metadata ??= new List<Annotation>();
metadata.add(parseAnnotation());
Comment optionalComment = _parseDocumentationComment();
if (optionalComment != null) {
comment = optionalComment;
}
}
+ metadata ??= const <Annotation>[];
return new CommentAndMetadata(comment, metadata);
}
@@ -5180,7 +5183,7 @@
return _convertToFunctionDeclaration(_parseOperator(
commentAndMetadata, modifiers.externalKeyword, returnType));
} else if (_matchesIdentifier() &&
- _peek().matchesAny([
+ _peek().matchesAny(const <TokenType>[
TokenType.OPEN_PAREN,
TokenType.OPEN_CURLY_BRACKET,
TokenType.FUNCTION,
@@ -5194,8 +5197,11 @@
// We have found an error of some kind. Try to recover.
//
if (_matchesIdentifier()) {
- if (_peek().matchesAny(
- [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
+ if (_peek().matchesAny(const <TokenType>[
+ TokenType.EQ,
+ TokenType.COMMA,
+ TokenType.SEMICOLON
+ ])) {
//
// We appear to have a variable declaration with a type of "void".
//
@@ -5253,8 +5259,11 @@
_validateModifiersForTopLevelFunction(modifiers);
return _parseFunctionDeclaration(
commentAndMetadata, modifiers.externalKeyword, returnType);
- } else if (_peek()
- .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
+ } else if (_peek().matchesAny(const <TokenType>[
+ TokenType.EQ,
+ TokenType.COMMA,
+ TokenType.SEMICOLON
+ ])) {
if (modifiers.constKeyword == null &&
modifiers.finalKeyword == null &&
modifiers.varKeyword == null) {
@@ -5304,7 +5313,7 @@
new VariableDeclarationList(null, null, null, returnType, variables),
semicolon);
}
- if (_peek().matchesAny([
+ if (_peek().matchesAny(const <TokenType>[
TokenType.OPEN_PAREN,
TokenType.FUNCTION,
TokenType.OPEN_CURLY_BRACKET,
@@ -5360,10 +5369,8 @@
*/
List<Configuration> _parseConfigurations() {
List<Configuration> configurations = <Configuration>[];
- if (parseConditionalDirectives) {
- while (_matchesKeyword(Keyword.IF)) {
- configurations.add(_parseConfiguration());
- }
+ while (_matchesKeyword(Keyword.IF)) {
+ configurations.add(_parseConfiguration());
}
return configurations;
}
@@ -6288,7 +6295,7 @@
_parseFunctionDeclaration(commentAndMetadata, null, returnType);
Token propertyKeyword = declaration.propertyKeyword;
if (propertyKeyword != null) {
- if ((propertyKeyword as KeywordToken).keyword == Keyword.GET) {
+ if (propertyKeyword.keyword == Keyword.GET) {
_reportErrorForToken(
ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword);
} else {
@@ -7023,8 +7030,8 @@
}
return parseBlock();
} else if (_matches(TokenType.KEYWORD) &&
- !(_currentToken as KeywordToken).keyword.isPseudoKeyword) {
- Keyword keyword = (_currentToken as KeywordToken).keyword;
+ !_currentToken.keyword.isPseudoKeyword) {
+ Keyword keyword = _currentToken.keyword;
// TODO(jwren) compute some metrics to figure out a better order for this
// if-then sequence to optimize performance
if (keyword == Keyword.ASSERT) {
@@ -7059,7 +7066,7 @@
} else if (keyword == Keyword.VOID) {
TypeName returnType = parseReturnType();
if (_matchesIdentifier() &&
- _peek().matchesAny([
+ _peek().matchesAny(const <TokenType>[
TokenType.OPEN_PAREN,
TokenType.OPEN_CURLY_BRACKET,
TokenType.FUNCTION,
@@ -7072,8 +7079,11 @@
// We have found an error of some kind. Try to recover.
//
if (_matchesIdentifier()) {
- if (_peek().matchesAny(
- [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
+ if (_peek().matchesAny(const <TokenType>[
+ TokenType.EQ,
+ TokenType.COMMA,
+ TokenType.SEMICOLON
+ ])) {
//
// We appear to have a variable declaration with a type of "void".
//
@@ -7094,7 +7104,7 @@
return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
}
} else if (keyword == Keyword.CONST) {
- if (_peek().matchesAny([
+ if (_peek().matchesAny(const <TokenType>[
TokenType.LT,
TokenType.OPEN_CURLY_BRACKET,
TokenType.OPEN_SQUARE_BRACKET,
@@ -7323,10 +7333,14 @@
if (_isLikelyArgumentList()) {
TypeArgumentList typeArguments = _parseOptionalTypeArguments();
ArgumentList argumentList = parseArgumentList();
- if (operand is PropertyAccess) {
- PropertyAccess access = operand as PropertyAccess;
- operand = new MethodInvocation(access.target, access.operator,
- access.propertyName, typeArguments, argumentList);
+ Expression currentOperand = operand;
+ if (currentOperand is PropertyAccess) {
+ operand = new MethodInvocation(
+ currentOperand.target,
+ currentOperand.operator,
+ currentOperand.propertyName,
+ typeArguments,
+ argumentList);
} else {
operand = new FunctionExpressionInvocation(
operand, typeArguments, argumentList);
@@ -8483,14 +8497,15 @@
// Look to see whether the token after the open parenthesis is something
// that should only occur at the beginning of a parameter list.
//
- if (next.matchesAny([
+ if (next.matchesAny(const <TokenType>[
TokenType.AT,
TokenType.OPEN_SQUARE_BRACKET,
TokenType.OPEN_CURLY_BRACKET
]) ||
_tokenMatchesKeyword(next, Keyword.VOID) ||
(_tokenMatchesIdentifier(next) &&
- (next.next.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN])))) {
+ (next.next.matchesAny(
+ const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])))) {
return _skipPastMatchingToken(startToken);
}
//
@@ -8501,8 +8516,8 @@
_tokenMatches(next.next, TokenType.OPEN_PAREN)) {
Token afterParameters = _skipFormalParameterList(next.next);
if (afterParameters != null &&
- (afterParameters
- .matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN]))) {
+ afterParameters.matchesAny(
+ const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])) {
return _skipPastMatchingToken(startToken);
}
}
@@ -8833,15 +8848,13 @@
* Return `true` if the given [token] matches the given [keyword].
*/
bool _tokenMatchesKeyword(Token token, Keyword keyword) =>
- token.type == TokenType.KEYWORD &&
- (token as KeywordToken).keyword == keyword;
+ token.keyword == keyword;
/**
* Return `true` if the given [token] matches a pseudo keyword.
*/
bool _tokenMatchesPseudoKeyword(Token token) =>
- _tokenMatches(token, TokenType.KEYWORD) &&
- (token as KeywordToken).keyword.isPseudoKeyword;
+ token.keyword?.isPseudoKeyword ?? false;
/**
* Return `true` if the given [token] matches the given [identifier].
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 3f1c0ed..3b06ea0 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -13,12 +13,12 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/utilities.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -33,6 +33,8 @@
import 'package:analyzer/src/task/strong/info.dart'
show InferredType, StaticInfo;
+export 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+export 'package:analyzer/src/dart/resolver/scope.dart';
export 'package:analyzer/src/generated/type_system.dart';
/**
@@ -519,10 +521,12 @@
if (element == null) {
return false;
} else if (element is PropertyAccessorElement && element.isSynthetic) {
- element = (element as PropertyAccessorElement).variable;
- if (element == null) {
+ // TODO(brianwilkerson) Why isn't this the implementation for PropertyAccessorElement?
+ Element variable = element.variable;
+ if (variable == null) {
return false;
}
+ return variable.isDeprecated;
}
return element.isDeprecated;
}
@@ -532,10 +536,9 @@
// TODO(jwren) We should modify ConstructorElement.getDisplayName(),
// or have the logic centralized elsewhere, instead of doing this logic
// here.
- ConstructorElement constructorElement = element;
- displayName = constructorElement.enclosingElement.displayName;
- if (!constructorElement.displayName.isEmpty) {
- displayName = "$displayName.${constructorElement.displayName}";
+ displayName = element.enclosingElement.displayName;
+ if (!element.displayName.isEmpty) {
+ displayName = "$displayName.${element.displayName}";
}
}
_errorReporter.reportErrorForNode(
@@ -596,16 +599,16 @@
return false;
}
// Report error if the (x/y) has toInt() invoked on it
- if (node.parent is ParenthesizedExpression) {
+ AstNode parent = node.parent;
+ if (parent is ParenthesizedExpression) {
ParenthesizedExpression parenthesizedExpression =
- _wrapParenthesizedExpression(node.parent as ParenthesizedExpression);
- if (parenthesizedExpression.parent is MethodInvocation) {
- MethodInvocation methodInvocation =
- parenthesizedExpression.parent as MethodInvocation;
- if (_TO_INT_METHOD_NAME == methodInvocation.methodName.name &&
- methodInvocation.argumentList.arguments.isEmpty) {
+ _wrapParenthesizedExpression(parent);
+ AstNode grandParent = parenthesizedExpression.parent;
+ if (grandParent is MethodInvocation) {
+ if (_TO_INT_METHOD_NAME == grandParent.methodName.name &&
+ grandParent.argumentList.arguments.isEmpty) {
_errorReporter.reportErrorForNode(
- HintCode.DIVISION_OPTIMIZATION, methodInvocation);
+ HintCode.DIVISION_OPTIMIZATION, grandParent);
return true;
}
}
@@ -750,38 +753,34 @@
* @return `true` if and only if a hint code is generated on the passed node
* See [HintCode.MISSING_RETURN].
*/
- bool _checkForMissingReturn(TypeName returnType, FunctionBody body) {
+ void _checkForMissingReturn(TypeName returnType, FunctionBody body) {
// Check that the method or function has a return type, and a function body
if (returnType == null || body == null) {
- return false;
+ return;
}
// Check that the body is a BlockFunctionBody
- if (body is! BlockFunctionBody) {
- return false;
+ if (body is BlockFunctionBody) {
+ // Generators are never required to have a return statement.
+ if (body.isGenerator) {
+ return;
+ }
+ // Check that the type is resolvable, and is not "void"
+ DartType returnTypeType = returnType.type;
+ if (returnTypeType == null || returnTypeType.isVoid) {
+ return;
+ }
+ // For async, give no hint if Future<Null> is assignable to the return
+ // type.
+ if (body.isAsynchronous &&
+ _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) {
+ return;
+ }
+ // Check the block for a return statement, if not, create the hint
+ if (!ExitDetector.exits(body)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
+ }
}
- // Generators are never required to have a return statement.
- if (body.isGenerator) {
- return false;
- }
- // Check that the type is resolvable, and is not "void"
- DartType returnTypeType = returnType.type;
- if (returnTypeType == null || returnTypeType.isVoid) {
- return false;
- }
- // For async, give no hint if Future<Null> is assignable to the return
- // type.
- if (body.isAsynchronous &&
- _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) {
- return false;
- }
- // Check the block for a return statement, if not, create the hint
- BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
- if (!ExitDetector.exits(blockFunctionBody)) {
- _errorReporter.reportErrorForNode(
- HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
- return true;
- }
- return false;
}
/**
@@ -972,28 +971,22 @@
// }
/**
- * Check for situations where the result of a method or function is used, when it returns 'void'.
+ * Check for situations where the result of a method or function is used, when
+ * it returns 'void'.
*
- * TODO(jwren) Many other situations of use could be covered. We currently cover the cases var x =
- * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m(), f(m()), return
- * m().
- *
- * @param node expression on the RHS of some assignment
- * @return `true` if and only if a hint code is generated on the passed node
* See [HintCode.USE_OF_VOID_RESULT].
*/
- bool _checkForUseOfVoidResult(Expression expression) {
- if (expression == null || expression is! MethodInvocation) {
- return false;
+ void _checkForUseOfVoidResult(Expression expression) {
+ // TODO(jwren) Many other situations of use could be covered. We currently
+ // cover the cases var x = m() and x = m(), but we could also cover cases
+ // such as m().x, m()[k], a + m(), f(m()), return m().
+ if (expression is MethodInvocation) {
+ if (identical(expression.staticType, VoidTypeImpl.instance)) {
+ SimpleIdentifier methodName = expression.methodName;
+ _errorReporter.reportErrorForNode(
+ HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
+ }
}
- MethodInvocation methodInvocation = expression as MethodInvocation;
- if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) {
- SimpleIdentifier methodName = methodInvocation.methodName;
- _errorReporter.reportErrorForNode(
- HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
- return true;
- }
- return false;
}
bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) {
@@ -1027,9 +1020,9 @@
*/
static ParenthesizedExpression _wrapParenthesizedExpression(
ParenthesizedExpression parenthesizedExpression) {
- if (parenthesizedExpression.parent is ParenthesizedExpression) {
- return _wrapParenthesizedExpression(
- parenthesizedExpression.parent as ParenthesizedExpression);
+ AstNode parent = parenthesizedExpression.parent;
+ if (parent is ParenthesizedExpression) {
+ return _wrapParenthesizedExpression(parent);
}
return parenthesizedExpression;
}
@@ -1093,61 +1086,6 @@
}
/**
- * Instances of the class `ClassScope` implement the scope defined by a class.
- */
-class ClassScope extends EnclosedScope {
- /**
- * 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 represented by this scope
- */
- ClassScope(Scope enclosingScope, ClassElement typeElement)
- : super(enclosingScope) {
- if (typeElement == null) {
- throw new IllegalArgumentException("class element cannot be null");
- }
- _defineMembers(typeElement);
- }
-
- @override
- AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
- if (existing is PropertyAccessorElement && duplicate is MethodElement) {
- if (existing.nameOffset < duplicate.nameOffset) {
- return new AnalysisError(
- duplicate.source,
- duplicate.nameOffset,
- duplicate.nameLength,
- CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
- [existing.displayName]);
- } else {
- return new AnalysisError(
- existing.source,
- existing.nameOffset,
- existing.nameLength,
- CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
- [existing.displayName]);
- }
- }
- return super.getErrorForDuplicate(existing, duplicate);
- }
-
- /**
- * Define the instance members defined by the class.
- *
- * @param typeElement the element representing the type represented by this scope
- */
- void _defineMembers(ClassElement typeElement) {
- for (PropertyAccessorElement accessor in typeElement.accessors) {
- define(accessor);
- }
- for (MethodElement method in typeElement.methods) {
- define(method);
- }
- }
-}
-
-/**
* Instances of the class `ConstantVerifier` traverse an AST structure looking for additional
* errors and warnings not covered by the parser and resolver. In particular, it looks for errors
* and warnings related to constant expressions.
@@ -1219,9 +1157,8 @@
// check annotation creation
Element element = node.element;
if (element is ConstructorElement) {
- ConstructorElement constructorElement = element;
- // should 'const' constructor
- if (!constructorElement.isConst) {
+ // should be 'const' constructor
+ if (!element.isConst) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node);
return null;
@@ -1384,8 +1321,7 @@
DartType firstType = null;
for (SwitchMember switchMember in switchMembers) {
if (switchMember is SwitchCase) {
- SwitchCase switchCase = switchMember;
- Expression expression = switchCase.expression;
+ Expression expression = switchMember.expression;
DartObjectImpl caseResult = _validate(
expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION);
if (caseResult != null) {
@@ -1475,18 +1411,17 @@
}
// prepare ClassElement
Element element = type.element;
- if (element is! ClassElement) {
- return false;
+ if (element is ClassElement) {
+ // lookup for ==
+ MethodElement method =
+ element.lookUpConcreteMethod("==", _currentLibrary);
+ if (method == null || method.enclosingElement.type.isObject) {
+ return false;
+ }
+ // there is == that we don't like
+ return true;
}
- ClassElement classElement = element as ClassElement;
- // lookup for ==
- MethodElement method =
- classElement.lookUpConcreteMethod("==", _currentLibrary);
- if (method == null || method.enclosingElement.type.isObject) {
- return false;
- }
- // there is == that we don't like
- return true;
+ return false;
}
/**
@@ -1573,11 +1508,10 @@
*/
void _validateConstantArguments(ArgumentList argumentList) {
for (Expression argument in argumentList.arguments) {
- if (argument is NamedExpression) {
- argument = (argument as NamedExpression).expression;
- }
+ Expression realArgument =
+ argument is NamedExpression ? argument.expression : argument;
_validate(
- argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
+ realArgument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
}
}
@@ -1593,19 +1527,16 @@
NodeList<ConstructorInitializer> initializers = constructor.initializers;
for (ConstructorInitializer initializer in initializers) {
if (initializer is ConstructorFieldInitializer) {
- ConstructorFieldInitializer fieldInitializer = initializer;
_validateInitializerExpression(
- parameterElements, fieldInitializer.expression);
+ parameterElements, initializer.expression);
}
if (initializer is RedirectingConstructorInvocation) {
- RedirectingConstructorInvocation invocation = initializer;
_validateInitializerInvocationArguments(
- parameterElements, invocation.argumentList);
+ parameterElements, initializer.argumentList);
}
if (initializer is SuperConstructorInvocation) {
- SuperConstructorInvocation invocation = initializer;
_validateInitializerInvocationArguments(
- parameterElements, invocation.argumentList);
+ parameterElements, initializer.argumentList);
}
}
}
@@ -1622,8 +1553,7 @@
}
for (FormalParameter parameter in parameters.parameters) {
if (parameter is DefaultFormalParameter) {
- DefaultFormalParameter defaultParameter = parameter;
- Expression defaultValue = defaultParameter.defaultValue;
+ Expression defaultValue = parameter.defaultValue;
DartObjectImpl result;
if (defaultValue == null) {
result =
@@ -1656,30 +1586,27 @@
ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) {
NodeList<ClassMember> members = classDeclaration.members;
for (ClassMember member in members) {
- if (member is FieldDeclaration) {
- FieldDeclaration fieldDeclaration = member;
- if (!fieldDeclaration.isStatic) {
- for (VariableDeclaration variableDeclaration
- in fieldDeclaration.fields.variables) {
- Expression initializer = variableDeclaration.initializer;
- if (initializer != null) {
- // Ignore any errors produced during validation--if the constant
- // can't be eavluated we'll just report a single error.
- AnalysisErrorListener errorListener =
- AnalysisErrorListener.NULL_LISTENER;
- ErrorReporter subErrorReporter =
- new ErrorReporter(errorListener, _errorReporter.source);
- DartObjectImpl result = initializer.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(_typeProvider, declaredVariables,
- typeSystem: _typeSystem),
- subErrorReporter));
- if (result == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode
- .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
- errorSite,
- [variableDeclaration.name.name]);
- }
+ if (member is FieldDeclaration && !member.isStatic) {
+ for (VariableDeclaration variableDeclaration
+ in member.fields.variables) {
+ Expression initializer = variableDeclaration.initializer;
+ if (initializer != null) {
+ // Ignore any errors produced during validation--if the constant
+ // can't be eavluated we'll just report a single error.
+ AnalysisErrorListener errorListener =
+ AnalysisErrorListener.NULL_LISTENER;
+ ErrorReporter subErrorReporter =
+ new ErrorReporter(errorListener, _errorReporter.source);
+ DartObjectImpl result = initializer.accept(new ConstantVisitor(
+ new ConstantEvaluationEngine(_typeProvider, declaredVariables,
+ typeSystem: _typeSystem),
+ subErrorReporter));
+ if (result == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
+ errorSite,
+ [variableDeclaration.name.name]);
}
}
}
@@ -1932,6 +1859,21 @@
}
@override
+ Object visitExportDirective(ExportDirective node) {
+ ExportElement exportElement = node.element;
+ if (exportElement != null) {
+ // The element is null when the URI is invalid
+ LibraryElement library = exportElement.exportedLibrary;
+ if (library != null) {
+ for (Combinator combinator in node.combinators) {
+ _checkCombinator(exportElement.exportedLibrary, combinator);
+ }
+ }
+ }
+ return super.visitExportDirective(node);
+ }
+
+ @override
Object visitIfStatement(IfStatement node) {
Expression conditionExpression = node.condition;
conditionExpression?.accept(this);
@@ -1961,6 +1903,21 @@
}
@override
+ Object visitImportDirective(ImportDirective node) {
+ ImportElement importElement = node.element;
+ if (importElement != null) {
+ // The element is null when the URI is invalid
+ LibraryElement library = importElement.importedLibrary;
+ if (library != null) {
+ for (Combinator combinator in node.combinators) {
+ _checkCombinator(library, combinator);
+ }
+ }
+ }
+ return super.visitImportDirective(node);
+ }
+
+ @override
Object visitSwitchCase(SwitchCase node) {
_checkForDeadStatementsInNodeList(node.statements);
return super.visitSwitchCase(node);
@@ -2060,6 +2017,35 @@
}
/**
+ * Resolve the names in the given [combinator] in the scope of the given
+ * [library].
+ */
+ void _checkCombinator(LibraryElement library, Combinator combinator) {
+ Namespace namespace =
+ new NamespaceBuilder().createExportNamespaceForLibrary(library);
+ NodeList<SimpleIdentifier> names;
+ ErrorCode hintCode;
+ if (combinator is HideCombinator) {
+ names = combinator.hiddenNames;
+ hintCode = HintCode.UNDEFINED_HIDDEN_NAME;
+ } else {
+ names = (combinator as ShowCombinator).shownNames;
+ hintCode = HintCode.UNDEFINED_SHOWN_NAME;
+ }
+ for (SimpleIdentifier name in names) {
+ String nameStr = name.name;
+ Element element = namespace.get(nameStr);
+ if (element == null) {
+ element = namespace.get("$nameStr=");
+ }
+ if (element == null) {
+ _errorReporter
+ .reportErrorForNode(hintCode, name, [library.identifier, nameStr]);
+ }
+ }
+ }
+
+ /**
* Given some [NodeList] of [Statement]s, from either a [Block] or
* [SwitchMember], this loops through the list in reverse order searching for statements
* after a return, unlabeled break or unlabeled continue statement to mark them as dead code.
@@ -2130,11 +2116,9 @@
bool _isDebugConstant(Expression expression) {
Element element = null;
if (expression is Identifier) {
- Identifier identifier = expression;
- element = identifier.staticElement;
+ element = expression.staticElement;
} else if (expression is PropertyAccess) {
- PropertyAccess propertyAccess = expression;
- element = propertyAccess.propertyName.staticElement;
+ element = expression.propertyName.staticElement;
}
if (element is PropertyAccessorElement) {
PropertyInducingElement variable = element.variable;
@@ -2388,9 +2372,9 @@
accessors = _enclosingUnit.accessors;
}
PropertyAccessorElement accessor;
- if ((property as KeywordToken).keyword == Keyword.GET) {
+ if (property.keyword == Keyword.GET) {
accessor = _findIdentifier(accessors, functionName);
- } else if ((property as KeywordToken).keyword == Keyword.SET) {
+ } else if (property.keyword == Keyword.SET) {
accessor = _findWithNameAndOffset(accessors, functionName,
functionName.name + '=', functionName.offset);
_expectedElements.remove(accessor);
@@ -2501,9 +2485,9 @@
methodName.staticElement = _enclosingExecutable;
} else {
PropertyAccessorElement accessor;
- if ((property as KeywordToken).keyword == Keyword.GET) {
+ if (property.keyword == Keyword.GET) {
accessor = _findIdentifier(_enclosingClass.accessors, methodName);
- } else if ((property as KeywordToken).keyword == Keyword.SET) {
+ } else if (property.keyword == Keyword.SET) {
accessor = _findWithNameAndOffset(_enclosingClass.accessors,
methodName, nameOfMethod + '=', methodName.offset);
_expectedElements.remove(accessor);
@@ -2847,7 +2831,7 @@
*/
ExportElement _findExport(
ExportDirective node, List<ExportElement> exports, Source source) {
- if (source == null || !_enclosingUnit.context.exists(source)) {
+ if (source == null) {
return null;
}
for (ExportElement export in exports) {
@@ -2862,6 +2846,9 @@
return export;
}
}
+ if (!_enclosingUnit.context.exists(source)) {
+ return null;
+ }
_mismatch("Could not find export element for '$source'", node);
return null; // Never reached
}
@@ -2873,7 +2860,7 @@
*/
ImportElement _findImport(
ImportDirective node, List<ImportElement> imports, Source source) {
- if (source == null || !_enclosingUnit.context.exists(source)) {
+ if (source == null) {
return null;
}
SimpleIdentifier prefix = node.prefix;
@@ -2895,6 +2882,9 @@
return element;
}
}
+ if (!_enclosingUnit.context.exists(source)) {
+ return null;
+ }
if (foundSource) {
if (prefix == null) {
_mismatch(
@@ -3291,80 +3281,6 @@
}
/**
- * Instances of the class `EnclosedScope` implement a scope that is lexically enclosed in
- * another scope.
- */
-class EnclosedScope extends Scope {
- /**
- * The scope in which this scope is lexically enclosed.
- */
- @override
- final Scope enclosingScope;
-
- /**
- * A table mapping names that will be defined in this scope, but right now are not initialized.
- * According to the scoping rules these names are hidden, even if they were defined in an outer
- * scope.
- */
- HashMap<String, Element> _hiddenElements = new HashMap<String, Element>();
-
- /**
- * A flag indicating whether there are any names defined in this scope.
- */
- bool _hasHiddenName = false;
-
- /**
- * Initialize a newly created scope enclosed within another scope.
- *
- * @param enclosingScope the scope in which this scope is lexically enclosed
- */
- EnclosedScope(this.enclosingScope);
-
- @override
- AnalysisErrorListener get errorListener => enclosingScope.errorListener;
-
- /**
- * Record that given element is declared in this scope, but hasn't been initialized yet, so it is
- * error to use. If there is already an element with the given name defined in an outer scope,
- * then it will become unavailable.
- *
- * @param element the element declared, but not initialized in this scope
- */
- void hide(Element element) {
- if (element != null) {
- String name = element.name;
- if (name != null && !name.isEmpty) {
- _hiddenElements[name] = element;
- _hasHiddenName = true;
- }
- }
- }
-
- @override
- Element internalLookup(
- Identifier identifier, String name, LibraryElement referencingLibrary) {
- Element element = localLookup(name, referencingLibrary);
- if (element != null) {
- return element;
- }
- // May be there is a hidden Element.
- if (_hasHiddenName) {
- Element hiddenElement = _hiddenElements[name];
- if (hiddenElement != null) {
- errorListener.onError(new AnalysisError(
- getSource(identifier),
- identifier.offset,
- identifier.length,
- CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
- return hiddenElement;
- }
- }
- // Check enclosing scope.
- return enclosingScope.internalLookup(identifier, name, referencingLibrary);
- }
-}
-
-/**
* Instances of the class `EnumMemberBuilder` build the members in enum declarations.
*/
class EnumMemberBuilder extends RecursiveAstVisitor<Object> {
@@ -3553,8 +3469,7 @@
// evaluates to a constant false value?
if (operatorType == TokenType.BAR_BAR) {
if (lhsExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = lhsExpression;
- if (!booleanLiteral.value) {
+ if (!lhsExpression.value) {
return _nodeExits(rhsExpression);
}
}
@@ -3564,8 +3479,7 @@
// expression if the left hand side is the true literal.
if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
if (lhsExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = lhsExpression;
- if (booleanLiteral.value) {
+ if (lhsExpression.value) {
return _nodeExits(rhsExpression);
}
}
@@ -3626,11 +3540,10 @@
}
// TODO(jwren) Do we want to take all constant expressions into account?
if (conditionExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = conditionExpression;
// If do {} while (true), and the body doesn't return or the body
// doesn't have a break, then return true.
bool blockReturns = _nodeExits(node.body);
- if (booleanLiteral.value &&
+ if (conditionExpression.value &&
(blockReturns || !_enclosingBlockContainsBreak)) {
return true;
}
@@ -3723,8 +3636,7 @@
}
// TODO(jwren) Do we want to take all constant expressions into account?
if (conditionExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = conditionExpression;
- if (booleanLiteral.value) {
+ if (conditionExpression.value) {
// if(true) ...
return _nodeExits(thenStatement);
} else if (elseStatement != null) {
@@ -3918,11 +3830,10 @@
}
// TODO(jwren) Do we want to take all constant expressions into account?
if (conditionExpression is BooleanLiteral) {
- BooleanLiteral booleanLiteral = conditionExpression;
// If while(true), and the body doesn't return or the body doesn't have
// a break, then return true.
bool blockReturns = node.body.accept(this);
- if (booleanLiteral.value &&
+ if (conditionExpression.value &&
(blockReturns || !_enclosingBlockContainsBreak)) {
return true;
}
@@ -3983,103 +3894,6 @@
}
/**
- * 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 the [enclosingScope] that
- * represents the given [_functionElement].
- */
- FunctionScope(Scope enclosingScope, this._functionElement)
- : 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.
- */
- void defineParameters() {
- if (_parametersDefined) {
- return;
- }
- _parametersDefined = true;
- Scope parameterScope = enclosingScope;
- for (ParameterElement parameter in _functionElement.parameters) {
- if (!parameter.isInitializingFormal) {
- parameterScope.define(parameter);
- }
- }
- }
-
- /**
- * Define the type parameters for the function.
- */
- void _defineTypeParameters() {
- Scope typeParameterScope = enclosingScope.enclosingScope;
- for (TypeParameterElement typeParameter
- in _functionElement.typeParameters) {
- typeParameterScope.define(typeParameter);
- }
- }
-}
-
-/**
- * The scope defined by a function type alias.
- */
-class FunctionTypeScope extends EnclosedScope {
- final FunctionTypeAliasElement _typeElement;
-
- bool _parametersDefined = false;
-
- /**
- * Initialize a newly created scope enclosed within the [enclosingScope] that
- * represents the given [_typeElement].
- */
- FunctionTypeScope(Scope enclosingScope, this._typeElement)
- : super(new EnclosedScope(enclosingScope)) {
- _defineTypeParameters();
- }
-
- /**
- * Define the parameters for the function type alias.
- */
- void defineParameters() {
- if (_parametersDefined) {
- return;
- }
- _parametersDefined = true;
- for (ParameterElement parameter in _typeElement.parameters) {
- define(parameter);
- }
- }
-
- /**
- * Define the type parameters for the function type alias.
- */
- void _defineTypeParameters() {
- Scope typeParameterScope = enclosingScope;
- for (TypeParameterElement typeParameter in _typeElement.typeParameters) {
- typeParameterScope.define(typeParameter);
- }
- }
-}
-
-/**
* A visitor that visits ASTs and fills [UsedImportedElements].
*/
class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
@@ -4109,6 +3923,30 @@
}
/**
+ * If the given [identifier] is prefixed with a [PrefixElement], fill the
+ * corresponding `UsedImportedElements.prefixMap` entry and return `true`.
+ */
+ bool _recordPrefixMap(SimpleIdentifier identifier, Element element) {
+ bool recordIfTargetIsPrefixElement(Expression target) {
+ if (target is SimpleIdentifier && target.staticElement is PrefixElement) {
+ List<Element> prefixedElements = usedElements.prefixMap
+ .putIfAbsent(target.staticElement, () => <Element>[]);
+ prefixedElements.add(element);
+ return true;
+ }
+ return false;
+ }
+ AstNode parent = identifier.parent;
+ if (parent is MethodInvocation && parent.methodName == identifier) {
+ return recordIfTargetIsPrefixElement(parent.target);
+ }
+ if (parent is PrefixedIdentifier && parent.identifier == identifier) {
+ return recordIfTargetIsPrefixElement(parent.prefix);
+ }
+ return false;
+ }
+
+ /**
* Visit identifiers used by the given [directive].
*/
void _visitDirective(Directive directive) {
@@ -4123,8 +3961,7 @@
// If the element is multiply defined then call this method recursively for
// each of the conflicting elements.
if (element is MultiplyDefinedElement) {
- MultiplyDefinedElement multiplyDefinedElement = element;
- for (Element elt in multiplyDefinedElement.conflictingElements) {
+ for (Element elt in element.conflictingElements) {
_visitIdentifier(identifier, elt);
}
return;
@@ -4157,30 +3994,6 @@
// Remember the element.
usedElements.elements.add(element);
}
-
- /**
- * If the given [identifier] is prefixed with a [PrefixElement], fill the
- * corresponding `UsedImportedElements.prefixMap` entry and return `true`.
- */
- bool _recordPrefixMap(SimpleIdentifier identifier, Element element) {
- bool recordIfTargetIsPrefixElement(Expression target) {
- if (target is SimpleIdentifier && target.staticElement is PrefixElement) {
- List<Element> prefixedElements = usedElements.prefixMap
- .putIfAbsent(target.staticElement, () => <Element>[]);
- prefixedElements.add(element);
- return true;
- }
- return false;
- }
- AstNode parent = identifier.parent;
- if (parent is MethodInvocation && parent.methodName == identifier) {
- return recordIfTargetIsPrefixElement(parent.target);
- }
- if (parent is PrefixedIdentifier && parent.identifier == identifier) {
- return recordIfTargetIsPrefixElement(parent.prefix);
- }
- return false;
- }
}
/**
@@ -4422,57 +4235,6 @@
}
/**
- * Instances of the class `ImplicitLabelScope` represent the scope statements
- * that can be the target of unlabeled break and continue statements.
- */
-class ImplicitLabelScope {
- /**
- * The implicit label scope associated with the top level of a function.
- */
- static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null);
-
- /**
- * The implicit label scope enclosing this implicit label scope.
- */
- final ImplicitLabelScope outerScope;
-
- /**
- * The statement that acts as a target for break and/or continue statements
- * at this scoping level.
- */
- final Statement statement;
-
- /**
- * Private constructor.
- */
- const ImplicitLabelScope._(this.outerScope, this.statement);
-
- /**
- * Get the statement which should be the target of an unlabeled `break` or
- * `continue` statement, or `null` if there is no appropriate target.
- */
- Statement getTarget(bool isContinue) {
- if (outerScope == null) {
- // This scope represents the toplevel of a function body, so it doesn't
- // match either break or continue.
- return null;
- }
- if (isContinue && statement is SwitchStatement) {
- return outerScope.getTarget(isContinue);
- }
- return statement;
- }
-
- /**
- * Initialize a newly created scope to represent a switch statement or loop
- * nested within the current scope. [statement] is the statement associated
- * with the newly created scope.
- */
- ImplicitLabelScope nest(Statement statement) =>
- new ImplicitLabelScope._(this, statement);
-}
-
-/**
* Instances of the class `ImportsVerifier` visit all of the referenced libraries in the source code
* verifying that all of the imports are used, otherwise a [HintCode.UNUSED_IMPORT] hint is
* generated with [generateUnusedImportHints].
@@ -4556,27 +4318,25 @@
void addImports(CompilationUnit node) {
for (Directive directive in node.directives) {
if (directive is ImportDirective) {
- ImportDirective importDirective = directive;
- LibraryElement libraryElement = importDirective.uriElement;
+ LibraryElement libraryElement = directive.uriElement;
if (libraryElement == null) {
continue;
}
- _unusedImports.add(importDirective);
+ _unusedImports.add(directive);
//
// Initialize prefixElementMap
//
- if (importDirective.asKeyword != null) {
- SimpleIdentifier prefixIdentifier = importDirective.prefix;
+ if (directive.asKeyword != null) {
+ SimpleIdentifier prefixIdentifier = directive.prefix;
if (prefixIdentifier != null) {
Element element = prefixIdentifier.staticElement;
if (element is PrefixElement) {
- PrefixElement prefixElementKey = element;
- List<ImportDirective> list = _prefixElementMap[prefixElementKey];
+ List<ImportDirective> list = _prefixElementMap[element];
if (list == null) {
list = new List<ImportDirective>();
- _prefixElementMap[prefixElementKey] = list;
+ _prefixElementMap[element] = list;
}
- list.add(importDirective);
+ list.add(directive);
}
// TODO (jwren) Can the element ever not be a PrefixElement?
}
@@ -4584,14 +4344,14 @@
//
// Initialize libraryMap: libraryElement -> importDirective
//
- _putIntoLibraryMap(libraryElement, importDirective);
+ _putIntoLibraryMap(libraryElement, directive);
//
// For this new addition to the libraryMap, also recursively add any
// exports from the libraryElement.
//
_addAdditionalLibrariesForExports(
- libraryElement, importDirective, new List<LibraryElement>());
- _addShownNames(importDirective);
+ libraryElement, directive, new HashSet<LibraryElement>());
+ _addShownNames(directive);
}
}
if (_unusedImports.length > 1) {
@@ -4738,15 +4498,15 @@
* Recursively add any exported library elements into the [libraryMap].
*/
void _addAdditionalLibrariesForExports(LibraryElement library,
- ImportDirective importDirective, List<LibraryElement> exportPath) {
- if (exportPath.contains(library)) {
+ ImportDirective importDirective, Set<LibraryElement> visitedLibraries) {
+ if (!visitedLibraries.add(library)) {
return;
}
- exportPath.add(library);
- for (LibraryElement exportedLibraryElt in library.exportedLibraries) {
- _putIntoLibraryMap(exportedLibraryElt, importDirective);
+ for (ExportElement exportElt in library.exports) {
+ LibraryElement exportedLibrary = exportElt.exportedLibrary;
+ _putIntoLibraryMap(exportedLibrary, importDirective);
_addAdditionalLibrariesForExports(
- exportedLibraryElt, importDirective, exportPath);
+ exportedLibrary, importDirective, visitedLibraries);
}
}
@@ -5105,1041 +4865,6 @@
}
/**
- * Instances of the class `InheritanceManager` manage the knowledge of where class members
- * (methods, getters & setters) are inherited from.
- */
-class InheritanceManager {
- /**
- * The [LibraryElement] that is managed by this manager.
- */
- LibraryElement _library;
-
- /**
- * This is a mapping between each [ClassElement] and a map between the [String] member
- * names and the associated [ExecutableElement] in the mixin and superclass chain.
- */
- HashMap<ClassElement, MemberMap> _classLookup;
-
- /**
- * This is a mapping between each [ClassElement] and a map between the [String] member
- * names and the associated [ExecutableElement] in the interface set.
- */
- HashMap<ClassElement, MemberMap> _interfaceLookup;
-
- /**
- * A map between each visited [ClassElement] and the set of [AnalysisError]s found on
- * the class element.
- */
- HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement =
- new HashMap<ClassElement, HashSet<AnalysisError>>();
-
- /**
- * Initialize a newly created inheritance manager.
- *
- * @param library the library element context that the inheritance mappings are being generated
- */
- InheritanceManager(LibraryElement library) {
- this._library = library;
- _classLookup = new HashMap<ClassElement, MemberMap>();
- _interfaceLookup = new HashMap<ClassElement, MemberMap>();
- }
-
- /**
- * Set the new library element context.
- *
- * @param library the new library element
- */
- void set libraryElement(LibraryElement library) {
- this._library = library;
- }
-
- /**
- * Return the set of [AnalysisError]s found on the passed [ClassElement], or
- * `null` if there are none.
- *
- * @param classElt the class element to query
- * @return the set of [AnalysisError]s found on the passed [ClassElement], or
- * `null` if there are none
- */
- HashSet<AnalysisError> getErrors(ClassElement classElt) =>
- _errorsInClassElement[classElt];
-
- /**
- * Get and return a mapping between the set of all string names of the members inherited from the
- * passed [ClassElement] superclass hierarchy, and the associated [ExecutableElement].
- *
- * @param classElt the class element to query
- * @return a mapping between the set of all members inherited from the passed [ClassElement]
- * superclass hierarchy, and the associated [ExecutableElement]
- */
- MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) =>
- _computeClassChainLookupMap(classElt, new HashSet<ClassElement>());
-
- /**
- * Get and return a mapping between the set of all string names of the members inherited from the
- * passed [ClassElement] interface hierarchy, and the associated [ExecutableElement].
- *
- * @param classElt the class element to query
- * @return a mapping between the set of all string names of the members inherited from the passed
- * [ClassElement] interface hierarchy, and the associated [ExecutableElement].
- */
- MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) =>
- _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>());
-
- /**
- * Given some [ClassElement] and some member name, this returns the
- * [ExecutableElement] that the class inherits from the mixins,
- * superclasses or interfaces, that has the member name, if no member is inherited `null` is
- * returned.
- *
- * @param classElt the class element to query
- * @param memberName the name of the executable element to find and return
- * @return the inherited executable element with the member name, or `null` if no such
- * member exists
- */
- ExecutableElement lookupInheritance(
- ClassElement classElt, String memberName) {
- if (memberName == null || memberName.isEmpty) {
- return null;
- }
- ExecutableElement executable =
- _computeClassChainLookupMap(classElt, new HashSet<ClassElement>())
- .get(memberName);
- if (executable == null) {
- return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>())
- .get(memberName);
- }
- return executable;
- }
-
- /**
- * Given some [ClassElement] and some member name, this returns the
- * [ExecutableElement] that the class either declares itself, or
- * inherits, that has the member name, if no member is inherited `null` is returned.
- *
- * @param classElt the class element to query
- * @param memberName the name of the executable element to find and return
- * @return the inherited executable element with the member name, or `null` if no such
- * member exists
- */
- ExecutableElement lookupMember(ClassElement classElt, String memberName) {
- ExecutableElement element = _lookupMemberInClass(classElt, memberName);
- if (element != null) {
- return element;
- }
- return lookupInheritance(classElt, memberName);
- }
-
- /**
- * Determine the set of methods which is overridden by the given class member. If no member is
- * inherited, an empty list is returned. If one of the inherited members is a
- * [MultiplyInheritedExecutableElement], then it is expanded into its constituent inherited
- * elements.
- *
- * @param classElt the class to query
- * @param memberName the name of the class member to query
- * @return a list of overridden methods
- */
- List<ExecutableElement> lookupOverrides(
- ClassElement classElt, String memberName) {
- List<ExecutableElement> result = new List<ExecutableElement>();
- if (memberName == null || memberName.isEmpty) {
- return result;
- }
- List<MemberMap> interfaceMaps =
- _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>());
- if (interfaceMaps != null) {
- for (MemberMap interfaceMap in interfaceMaps) {
- ExecutableElement overriddenElement = interfaceMap.get(memberName);
- if (overriddenElement != null) {
- if (overriddenElement is MultiplyInheritedExecutableElement) {
- MultiplyInheritedExecutableElement multiplyInheritedElement =
- overriddenElement;
- for (ExecutableElement element
- in multiplyInheritedElement.inheritedElements) {
- result.add(element);
- }
- } else {
- result.add(overriddenElement);
- }
- }
- }
- }
- return result;
- }
-
- /**
- * This method takes some inherited [FunctionType], and resolves all the parameterized types
- * in the function type, dependent on the class in which it is being overridden.
- *
- * @param baseFunctionType the function type that is being overridden
- * @param memberName the name of the member, this is used to lookup the inheritance path of the
- * override
- * @param definingType the type that is overriding the member
- * @return the passed function type with any parameterized types substituted
- */
- // TODO(jmesserly): investigate why this is needed in ErrorVerifier's override
- // checking. There seems to be some rare cases where we get partially
- // substituted type arguments, and the function types don't compare equally.
- FunctionType substituteTypeArgumentsInMemberFromInheritance(
- FunctionType baseFunctionType,
- String memberName,
- InterfaceType definingType) {
- // if the baseFunctionType is null, or does not have any parameters,
- // return it.
- if (baseFunctionType == null ||
- baseFunctionType.typeArguments.length == 0) {
- return baseFunctionType;
- }
- // First, generate the path from the defining type to the overridden member
- Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
- _computeInheritancePath(inheritancePath, definingType, memberName);
- if (inheritancePath == null || inheritancePath.isEmpty) {
- // TODO(jwren) log analysis engine error
- return baseFunctionType;
- }
- FunctionType functionTypeToReturn = baseFunctionType;
- // loop backward through the list substituting as we go:
- while (!inheritancePath.isEmpty) {
- InterfaceType lastType = inheritancePath.removeLast();
- List<DartType> parameterTypes = lastType.element.type.typeArguments;
- List<DartType> argumentTypes = lastType.typeArguments;
- functionTypeToReturn =
- functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
- }
- return functionTypeToReturn;
- }
-
- /**
- * Compute and return a mapping between the set of all string names of the members inherited from
- * the passed [ClassElement] superclass hierarchy, and the associated
- * [ExecutableElement].
- *
- * @param classElt the class element to query
- * @param visitedClasses a set of visited classes passed back into this method when it calls
- * itself recursively
- * @return a mapping between the set of all string names of the members inherited from the passed
- * [ClassElement] superclass hierarchy, and the associated [ExecutableElement]
- */
- MemberMap _computeClassChainLookupMap(
- ClassElement classElt, HashSet<ClassElement> visitedClasses) {
- MemberMap resultMap = _classLookup[classElt];
- if (resultMap != null) {
- return resultMap;
- } else {
- resultMap = new MemberMap();
- }
- ClassElement superclassElt = null;
- InterfaceType supertype = classElt.supertype;
- if (supertype != null) {
- superclassElt = supertype.element;
- } else {
- // classElt is Object
- _classLookup[classElt] = resultMap;
- return resultMap;
- }
- if (superclassElt != null) {
- if (!visitedClasses.contains(superclassElt)) {
- visitedClasses.add(superclassElt);
- try {
- resultMap = new MemberMap.from(
- _computeClassChainLookupMap(superclassElt, visitedClasses));
- //
- // Substitute the super types down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(supertype, resultMap);
- //
- // Include the members from the superclass in the resultMap.
- //
- _recordMapWithClassMembers(resultMap, supertype, false);
- } finally {
- visitedClasses.remove(superclassElt);
- }
- } else {
- // This case happens only when the superclass was previously visited and
- // not in the lookup, meaning this is meant to shorten the compute for
- // recursive cases.
- _classLookup[superclassElt] = resultMap;
- return resultMap;
- }
- }
- //
- // Include the members from the mixins in the resultMap. If there are
- // multiple mixins, visit them in the order listed so that methods in later
- // mixins will overwrite identically-named methods in earlier mixins.
- //
- List<InterfaceType> mixins = classElt.mixins;
- for (InterfaceType mixin in mixins) {
- ClassElement mixinElement = mixin.element;
- if (mixinElement != null) {
- if (!visitedClasses.contains(mixinElement)) {
- visitedClasses.add(mixinElement);
- try {
- MemberMap map = new MemberMap.from(
- _computeClassChainLookupMap(mixinElement, visitedClasses));
- //
- // Substitute the super types down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(mixin, map);
- //
- // Include the members from the superclass in the resultMap.
- //
- _recordMapWithClassMembers(map, mixin, false);
- //
- // Add the members from map into result map.
- //
- for (int j = 0; j < map.size; j++) {
- String key = map.getKey(j);
- ExecutableElement value = map.getValue(j);
- if (key != null) {
- ClassElement definingClass = value
- .getAncestor((Element element) => element is ClassElement);
- if (!definingClass.type.isObject) {
- ExecutableElement existingValue = resultMap.get(key);
- if (existingValue == null ||
- (existingValue != null && !_isAbstract(value))) {
- resultMap.put(key, value);
- }
- }
- }
- }
- } finally {
- visitedClasses.remove(mixinElement);
- }
- } else {
- // This case happens only when the superclass was previously visited
- // and not in the lookup, meaning this is meant to shorten the compute
- // for recursive cases.
- _classLookup[mixinElement] = resultMap;
- return resultMap;
- }
- }
- }
- _classLookup[classElt] = resultMap;
- return resultMap;
- }
-
- /**
- * Compute and return the inheritance path given the context of a type and a member that is
- * overridden in the inheritance path (for which the type is in the path).
- *
- * @param chain the inheritance path that is built up as this method calls itself recursively,
- * when this method is called an empty [LinkedList] should be provided
- * @param currentType the current type in the inheritance path
- * @param memberName the name of the member that is being looked up the inheritance path
- */
- void _computeInheritancePath(Queue<InterfaceType> chain,
- InterfaceType currentType, String memberName) {
- // TODO (jwren) create a public version of this method which doesn't require
- // the initial chain to be provided, then provided tests for this
- // functionality in InheritanceManagerTest
- chain.add(currentType);
- ClassElement classElt = currentType.element;
- InterfaceType supertype = classElt.supertype;
- // Base case- reached Object
- if (supertype == null) {
- // Looked up the chain all the way to Object, return null.
- // This should never happen.
- return;
- }
- // If we are done, return the chain
- // We are not done if this is the first recursive call on this method.
- if (chain.length != 1) {
- // We are done however if the member is in this classElt
- if (_lookupMemberInClass(classElt, memberName) != null) {
- return;
- }
- }
- // Mixins- note that mixins call lookupMemberInClass, not lookupMember
- List<InterfaceType> mixins = classElt.mixins;
- for (int i = mixins.length - 1; i >= 0; i--) {
- ClassElement mixinElement = mixins[i].element;
- if (mixinElement != null) {
- ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
- if (elt != null) {
- // this is equivalent (but faster than) calling this method
- // recursively
- // (return computeInheritancePath(chain, mixins[i], memberName);)
- chain.add(mixins[i]);
- return;
- }
- }
- }
- // Superclass
- ClassElement superclassElt = supertype.element;
- if (lookupMember(superclassElt, memberName) != null) {
- _computeInheritancePath(chain, supertype, memberName);
- return;
- }
- // Interfaces
- List<InterfaceType> interfaces = classElt.interfaces;
- for (InterfaceType interfaceType in interfaces) {
- ClassElement interfaceElement = interfaceType.element;
- if (interfaceElement != null &&
- lookupMember(interfaceElement, memberName) != null) {
- _computeInheritancePath(chain, interfaceType, memberName);
- return;
- }
- }
- }
-
- /**
- * Compute and return a mapping between the set of all string names of the members inherited from
- * the passed [ClassElement] interface hierarchy, and the associated
- * [ExecutableElement].
- *
- * @param classElt the class element to query
- * @param visitedInterfaces a set of visited classes passed back into this method when it calls
- * itself recursively
- * @return a mapping between the set of all string names of the members inherited from the passed
- * [ClassElement] interface hierarchy, and the associated [ExecutableElement]
- */
- MemberMap _computeInterfaceLookupMap(
- ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
- MemberMap resultMap = _interfaceLookup[classElt];
- if (resultMap != null) {
- return resultMap;
- }
- List<MemberMap> lookupMaps =
- _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
- if (lookupMaps == null) {
- resultMap = new MemberMap();
- } else {
- HashMap<String, List<ExecutableElement>> unionMap =
- _unionInterfaceLookupMaps(lookupMaps);
- resultMap = _resolveInheritanceLookup(classElt, unionMap);
- }
- _interfaceLookup[classElt] = resultMap;
- return resultMap;
- }
-
- /**
- * Collect a list of interface lookup maps whose elements correspond to all of the classes
- * directly above [classElt] in the class hierarchy (the direct superclass if any, all
- * mixins, and all direct superinterfaces). Each item in the list is the interface lookup map
- * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
- * parameters appropriately substituted.
- *
- * @param classElt the class element to query
- * @param visitedInterfaces a set of visited classes passed back into this method when it calls
- * itself recursively
- * @return `null` if there was a problem (such as a loop in the class hierarchy) or if there
- * are no classes above this one in the class hierarchy. Otherwise, a list of interface
- * lookup maps.
- */
- List<MemberMap> _gatherInterfaceLookupMaps(
- ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
- InterfaceType supertype = classElt.supertype;
- ClassElement superclassElement =
- supertype != null ? supertype.element : null;
- List<InterfaceType> mixins = classElt.mixins;
- List<InterfaceType> interfaces = classElt.interfaces;
- // Recursively collect the list of mappings from all of the interface types
- List<MemberMap> lookupMaps = new List<MemberMap>();
- //
- // Superclass element
- //
- if (superclassElement != null) {
- if (!visitedInterfaces.contains(superclassElement)) {
- try {
- visitedInterfaces.add(superclassElement);
- //
- // Recursively compute the map for the super type.
- //
- MemberMap map =
- _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
- map = new MemberMap.from(map);
- //
- // Substitute the super type down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(supertype, map);
- //
- // Add any members from the super type into the map as well.
- //
- _recordMapWithClassMembers(map, supertype, true);
- lookupMaps.add(map);
- } finally {
- visitedInterfaces.remove(superclassElement);
- }
- } else {
- return null;
- }
- }
- //
- // Mixin elements
- //
- for (int i = mixins.length - 1; i >= 0; i--) {
- InterfaceType mixinType = mixins[i];
- ClassElement mixinElement = mixinType.element;
- if (mixinElement != null) {
- if (!visitedInterfaces.contains(mixinElement)) {
- try {
- visitedInterfaces.add(mixinElement);
- //
- // Recursively compute the map for the mixin.
- //
- MemberMap map =
- _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
- map = new MemberMap.from(map);
- //
- // Substitute the mixin type down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(mixinType, map);
- //
- // Add any members from the mixin type into the map as well.
- //
- _recordMapWithClassMembers(map, mixinType, true);
- lookupMaps.add(map);
- } finally {
- visitedInterfaces.remove(mixinElement);
- }
- } else {
- return null;
- }
- }
- }
- //
- // Interface elements
- //
- for (InterfaceType interfaceType in interfaces) {
- ClassElement interfaceElement = interfaceType.element;
- if (interfaceElement != null) {
- if (!visitedInterfaces.contains(interfaceElement)) {
- try {
- visitedInterfaces.add(interfaceElement);
- //
- // Recursively compute the map for the interfaces.
- //
- MemberMap map =
- _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
- map = new MemberMap.from(map);
- //
- // Substitute the supertypes down the hierarchy
- //
- _substituteTypeParametersDownHierarchy(interfaceType, map);
- //
- // And add any members from the interface into the map as well.
- //
- _recordMapWithClassMembers(map, interfaceType, true);
- lookupMaps.add(map);
- } finally {
- visitedInterfaces.remove(interfaceElement);
- }
- } else {
- return null;
- }
- }
- }
- if (lookupMaps.length == 0) {
- return null;
- }
- return lookupMaps;
- }
-
- /**
- * Given some [ClassElement], this method finds and returns the [ExecutableElement] of
- * the passed name in the class element. Static members, members in super types and members not
- * accessible from the current library are not considered.
- *
- * @param classElt the class element to query
- * @param memberName the name of the member to lookup in the class
- * @return the found [ExecutableElement], or `null` if no such member was found
- */
- ExecutableElement _lookupMemberInClass(
- ClassElement classElt, String memberName) {
- List<MethodElement> methods = classElt.methods;
- for (MethodElement method in methods) {
- if (memberName == method.name &&
- method.isAccessibleIn(_library) &&
- !method.isStatic) {
- return method;
- }
- }
- List<PropertyAccessorElement> accessors = classElt.accessors;
- for (PropertyAccessorElement accessor in accessors) {
- if (memberName == accessor.name &&
- accessor.isAccessibleIn(_library) &&
- !accessor.isStatic) {
- return accessor;
- }
- }
- return null;
- }
-
- /**
- * Record the passed map with the set of all members (methods, getters and setters) in the type
- * into the passed map.
- *
- * @param map some non-`null` map to put the methods and accessors from the passed
- * [ClassElement] into
- * @param type the type that will be recorded into the passed map
- * @param doIncludeAbstract `true` if abstract members will be put into the map
- */
- void _recordMapWithClassMembers(
- MemberMap map, InterfaceType type, bool doIncludeAbstract) {
- List<MethodElement> methods = type.methods;
- for (MethodElement method in methods) {
- if (method.isAccessibleIn(_library) &&
- !method.isStatic &&
- (doIncludeAbstract || !method.isAbstract)) {
- map.put(method.name, method);
- }
- }
- List<PropertyAccessorElement> accessors = type.accessors;
- for (PropertyAccessorElement accessor in accessors) {
- if (accessor.isAccessibleIn(_library) &&
- !accessor.isStatic &&
- (doIncludeAbstract || !accessor.isAbstract)) {
- map.put(accessor.name, accessor);
- }
- }
- }
-
- /**
- * This method is used to report errors on when they are found computing inheritance information.
- * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where these generated
- * error codes are reported back into the analysis engine.
- *
- * @param classElt the location of the source for which the exception occurred
- * @param offset the offset of the location of the error
- * @param length the length of the location of the error
- * @param errorCode the error code to be associated with this error
- * @param arguments the arguments used to build the error message
- */
- void _reportError(ClassElement classElt, int offset, int length,
- ErrorCode errorCode, List<Object> arguments) {
- HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
- if (errorSet == null) {
- errorSet = new HashSet<AnalysisError>();
- _errorsInClassElement[classElt] = errorSet;
- }
- errorSet.add(new AnalysisError(
- classElt.source, offset, length, errorCode, arguments));
- }
-
- /**
- * Given the set of methods defined by classes above [classElt] in the class hierarchy,
- * apply the appropriate inheritance rules to determine those methods inherited by or overridden
- * by [classElt]. Also report static warnings
- * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
- * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if appropriate.
- *
- * @param classElt the class element to query.
- * @param unionMap a mapping from method name to the set of unique (in terms of signature) methods
- * defined in superclasses of [classElt].
- * @return the inheritance lookup map for [classElt].
- */
- MemberMap _resolveInheritanceLookup(ClassElement classElt,
- HashMap<String, List<ExecutableElement>> unionMap) {
- MemberMap resultMap = new MemberMap();
- unionMap.forEach((String key, List<ExecutableElement> list) {
- int numOfEltsWithMatchingNames = list.length;
- if (numOfEltsWithMatchingNames == 1) {
- //
- // Example: class A inherits only 1 method named 'm'.
- // Since it is the only such method, it is inherited.
- // Another example: class A inherits 2 methods named 'm' from 2
- // different interfaces, but they both have the same signature, so it is
- // the method inherited.
- //
- resultMap.put(key, list[0]);
- } else {
- //
- // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
- //
- bool allMethods = true;
- bool allSetters = true;
- bool allGetters = true;
- for (ExecutableElement executableElement in list) {
- if (executableElement is PropertyAccessorElement) {
- allMethods = false;
- if (executableElement.isSetter) {
- allGetters = false;
- } else {
- allSetters = false;
- }
- } else {
- allGetters = false;
- allSetters = false;
- }
- }
- //
- // If there isn't a mixture of methods with getters, then continue,
- // otherwise create a warning.
- //
- if (allMethods || allGetters || allSetters) {
- //
- // Compute the element whose type is the subtype of all of the other
- // types.
- //
- List<ExecutableElement> elements = new List.from(list);
- List<FunctionType> executableElementTypes =
- new List<FunctionType>(numOfEltsWithMatchingNames);
- for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
- executableElementTypes[i] = elements[i].type;
- }
- List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
- for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
- FunctionType subtype = executableElementTypes[i];
- if (subtype == null) {
- continue;
- }
- bool subtypeOfAllTypes = true;
- TypeSystem typeSystem = _library.context.typeSystem;
- for (int j = 0;
- j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
- j++) {
- if (i != j) {
- if (!typeSystem.isSubtypeOf(
- subtype, executableElementTypes[j])) {
- subtypeOfAllTypes = false;
- break;
- }
- }
- }
- if (subtypeOfAllTypes) {
- subtypesOfAllOtherTypesIndexes.add(i);
- }
- }
- //
- // The following is split into three cases determined by the number of
- // elements in subtypesOfAllOtherTypes
- //
- if (subtypesOfAllOtherTypesIndexes.length == 1) {
- //
- // Example: class A inherited only 2 method named 'm'.
- // One has the function type '() -> dynamic' and one has the
- // function type '([int]) -> dynamic'. Since the second method is a
- // subtype of all the others, it is the inherited method.
- // Tests: InheritanceManagerTest.
- // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
- //
- resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
- } else {
- if (subtypesOfAllOtherTypesIndexes.isEmpty) {
- //
- // Determine if the current class has a method or accessor with
- // the member name, if it does then then this class does not
- // "inherit" from any of the supertypes. See issue 16134.
- //
- bool classHasMember = false;
- if (allMethods) {
- classHasMember = classElt.getMethod(key) != null;
- } else {
- List<PropertyAccessorElement> accessors = classElt.accessors;
- for (int i = 0; i < accessors.length; i++) {
- if (accessors[i].name == key) {
- classHasMember = true;
- }
- }
- }
- //
- // Example: class A inherited only 2 method named 'm'.
- // One has the function type '() -> int' and one has the function
- // type '() -> String'. Since neither is a subtype of the other,
- // we create a warning, and have this class inherit nothing.
- //
- if (!classHasMember) {
- String firstTwoFuntionTypesStr =
- "${executableElementTypes[0]}, ${executableElementTypes[1]}";
- _reportError(
- classElt,
- classElt.nameOffset,
- classElt.nameLength,
- StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
- [key, firstTwoFuntionTypesStr]);
- }
- } else {
- //
- // Example: class A inherits 2 methods named 'm'.
- // One has the function type '(int) -> dynamic' and one has the
- // function type '(num) -> dynamic'. Since they are both a subtype
- // of the other, a synthetic function '(dynamic) -> dynamic' is
- // inherited.
- // Tests: test_getMapOfMembersInheritedFromInterfaces_
- // union_multipleSubtypes_*
- //
- List<ExecutableElement> elementArrayToMerge =
- new List<ExecutableElement>(
- subtypesOfAllOtherTypesIndexes.length);
- for (int i = 0; i < elementArrayToMerge.length; i++) {
- elementArrayToMerge[i] =
- elements[subtypesOfAllOtherTypesIndexes[i]];
- }
- ExecutableElement mergedExecutableElement =
- _computeMergedExecutableElement(elementArrayToMerge);
- resultMap.put(key, mergedExecutableElement);
- }
- }
- } else {
- _reportError(
- classElt,
- classElt.nameOffset,
- classElt.nameLength,
- StaticWarningCode
- .INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD,
- [key]);
- }
- }
- });
- return resultMap;
- }
-
- /**
- * Loop through all of the members in some [MemberMap], performing type parameter
- * substitutions using a passed supertype.
- *
- * @param superType the supertype to substitute into the members of the [MemberMap]
- * @param map the MemberMap to perform the substitutions on
- */
- void _substituteTypeParametersDownHierarchy(
- InterfaceType superType, MemberMap map) {
- for (int i = 0; i < map.size; i++) {
- ExecutableElement executableElement = map.getValue(i);
- if (executableElement is MethodMember) {
- executableElement =
- MethodMember.from(executableElement as MethodMember, superType);
- map.setValue(i, executableElement);
- } else if (executableElement is PropertyAccessorMember) {
- executableElement = PropertyAccessorMember.from(
- executableElement as PropertyAccessorMember, superType);
- map.setValue(i, executableElement);
- }
- }
- }
-
- /**
- * Union all of the [lookupMaps] together into a single map, grouping the ExecutableElements
- * into a list where none of the elements are equal where equality is determined by having equal
- * function types. (We also take note too of the kind of the element: ()->int and () -> int may
- * not be equal if one is a getter and the other is a method.)
- *
- * @param lookupMaps the maps to be unioned together.
- * @return the resulting union map.
- */
- HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
- List<MemberMap> lookupMaps) {
- HashMap<String, List<ExecutableElement>> unionMap =
- new HashMap<String, List<ExecutableElement>>();
- for (MemberMap lookupMap in lookupMaps) {
- int lookupMapSize = lookupMap.size;
- for (int i = 0; i < lookupMapSize; i++) {
- // Get the string key, if null, break.
- String key = lookupMap.getKey(i);
- if (key == null) {
- break;
- }
- // Get the list value out of the unionMap
- List<ExecutableElement> list = unionMap[key];
- // If we haven't created such a map for this key yet, do create it and
- // put the list entry into the unionMap.
- if (list == null) {
- list = new List<ExecutableElement>();
- unionMap[key] = list;
- }
- // Fetch the entry out of this lookupMap
- ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
- if (list.isEmpty) {
- // If the list is empty, just the new value
- list.add(newExecutableElementEntry);
- } else {
- // Otherwise, only add the newExecutableElementEntry if it isn't
- // already in the list, this covers situation where a class inherits
- // two methods (or two getters) that are identical.
- bool alreadyInList = false;
- bool isMethod1 = newExecutableElementEntry is MethodElement;
- for (ExecutableElement executableElementInList in list) {
- bool isMethod2 = executableElementInList is MethodElement;
- if (isMethod1 == isMethod2 &&
- executableElementInList.type ==
- newExecutableElementEntry.type) {
- alreadyInList = true;
- break;
- }
- }
- if (!alreadyInList) {
- list.add(newExecutableElementEntry);
- }
- }
- }
- }
- return unionMap;
- }
-
- /**
- * Given some array of [ExecutableElement]s, this method creates a synthetic element as
- * described in 8.1.1:
- *
- * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional parameters of a
- * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote the number of
- * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denote the set of all
- * named parameters of the <i>m<sub>1</sub>, …, m<sub>k</sub></i>. Then let
- * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
- * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
- * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameters of type
- * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, named parameters
- * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
- *
- */
- static ExecutableElement _computeMergedExecutableElement(
- List<ExecutableElement> elementArrayToMerge) {
- int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
- int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
- Set<String> namedParametersList = new HashSet<String>();
- for (int i = 1; i < elementArrayToMerge.length; i++) {
- ExecutableElement element = elementArrayToMerge[i];
- int numOfPositionalParams = _getNumOfPositionalParameters(element);
- if (h < numOfPositionalParams) {
- h = numOfPositionalParams;
- }
- int numOfRequiredParams = _getNumOfRequiredParameters(element);
- if (r > numOfRequiredParams) {
- r = numOfRequiredParams;
- }
- namedParametersList.addAll(_getNamedParameterNames(element));
- }
- return _createSyntheticExecutableElement(
- elementArrayToMerge,
- elementArrayToMerge[0].displayName,
- r,
- h - r,
- new List.from(namedParametersList));
- }
-
- /**
- * Used by [computeMergedExecutableElement] to actually create the
- * synthetic element.
- *
- * @param elementArrayToMerge the array used to create the synthetic element
- * @param name the name of the method, getter or setter
- * @param numOfRequiredParameters the number of required parameters
- * @param numOfPositionalParameters the number of positional parameters
- * @param namedParameters the list of [String]s that are the named parameters
- * @return the created synthetic element
- */
- static ExecutableElement _createSyntheticExecutableElement(
- List<ExecutableElement> elementArrayToMerge,
- String name,
- int numOfRequiredParameters,
- int numOfPositionalParameters,
- List<String> namedParameters) {
- DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
- SimpleIdentifier nameIdentifier =
- new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0));
- ExecutableElementImpl executable;
- if (elementArrayToMerge[0] is MethodElement) {
- MultiplyInheritedMethodElementImpl unionedMethod =
- new MultiplyInheritedMethodElementImpl(nameIdentifier);
- unionedMethod.inheritedElements = elementArrayToMerge;
- executable = unionedMethod;
- } else {
- MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
- new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
- unionedPropertyAccessor.getter =
- (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
- unionedPropertyAccessor.setter =
- (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
- unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
- executable = unionedPropertyAccessor;
- }
- int numOfParameters = numOfRequiredParameters +
- numOfPositionalParameters +
- namedParameters.length;
- List<ParameterElement> parameters =
- new List<ParameterElement>(numOfParameters);
- int i = 0;
- for (int j = 0; j < numOfRequiredParameters; j++, i++) {
- ParameterElementImpl parameter = new ParameterElementImpl("", 0);
- parameter.type = dynamicType;
- parameter.parameterKind = ParameterKind.REQUIRED;
- parameters[i] = parameter;
- }
- for (int k = 0; k < numOfPositionalParameters; k++, i++) {
- ParameterElementImpl parameter = new ParameterElementImpl("", 0);
- parameter.type = dynamicType;
- parameter.parameterKind = ParameterKind.POSITIONAL;
- parameters[i] = parameter;
- }
- for (int m = 0; m < namedParameters.length; m++, i++) {
- ParameterElementImpl parameter =
- new ParameterElementImpl(namedParameters[m], 0);
- parameter.type = dynamicType;
- parameter.parameterKind = ParameterKind.NAMED;
- parameters[i] = parameter;
- }
- executable.returnType = dynamicType;
- executable.parameters = parameters;
- FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
- executable.type = methodType;
- return executable;
- }
-
- /**
- * Given some [ExecutableElement], return the list of named parameters.
- */
- static List<String> _getNamedParameterNames(
- ExecutableElement executableElement) {
- List<String> namedParameterNames = new List<String>();
- List<ParameterElement> parameters = executableElement.parameters;
- for (int i = 0; i < parameters.length; i++) {
- ParameterElement parameterElement = parameters[i];
- if (parameterElement.parameterKind == ParameterKind.NAMED) {
- namedParameterNames.add(parameterElement.name);
- }
- }
- return namedParameterNames;
- }
-
- /**
- * Given some [ExecutableElement] return the number of parameters of the specified kind.
- */
- static int _getNumOfParameters(
- ExecutableElement executableElement, ParameterKind parameterKind) {
- int parameterCount = 0;
- List<ParameterElement> parameters = executableElement.parameters;
- for (int i = 0; i < parameters.length; i++) {
- ParameterElement parameterElement = parameters[i];
- if (parameterElement.parameterKind == parameterKind) {
- parameterCount++;
- }
- }
- return parameterCount;
- }
-
- /**
- * Given some [ExecutableElement] return the number of positional parameters.
- *
- * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSITIONAL].
- */
- static int _getNumOfPositionalParameters(
- ExecutableElement executableElement) =>
- _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
- _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
-
- /**
- * Given some [ExecutableElement] return the number of required parameters.
- */
- static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
- _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
-
- /**
- * Given some [ExecutableElement] returns `true` if it is an abstract member of a
- * class.
- *
- * @param executableElement some [ExecutableElement] to evaluate
- * @return `true` if the given element is an abstract member of a class
- */
- static bool _isAbstract(ExecutableElement executableElement) {
- if (executableElement is MethodElement) {
- return executableElement.isAbstract;
- } else if (executableElement is PropertyAccessorElement) {
- return executableElement.isAbstract;
- }
- return false;
- }
-}
-
-/**
* This enum holds one of four states of a field initialization state through a constructor
* signature, not initialized, initialized in the field declaration, initialized in the field
* formal, and finally, initialized in the initializers list.
@@ -6167,798 +4892,92 @@
}
/**
- * Instances of the class `LabelScope` represent a scope in which a single label is defined.
+ * An AST visitor that is used to re-resolve the initializers of instance
+ * fields. Although this class is an AST visitor, clients are expected to use
+ * the method [resolveCompilationUnit] to run it over a compilation unit.
*/
-class LabelScope {
+class InstanceFieldResolverVisitor extends ResolverVisitor {
/**
- * The label scope enclosing this label scope.
- */
- final LabelScope _outerScope;
-
- /**
- * The label defined in this scope.
- */
- final String _label;
-
- /**
- * The element to which the label resolves.
- */
- final LabelElement element;
-
- /**
- * The AST node to which the label resolves.
- */
- final AstNode node;
-
- /**
- * Initialize a newly created scope to represent the label [_label].
- * [_outerScope] is the scope enclosing the new label scope. [node] is the
- * AST node the label resolves to. [element] is the element the label
- * resolves to.
- */
- LabelScope(this._outerScope, this._label, this.node, this.element);
-
- /**
- * Return the LabelScope which defines [targetLabel], or `null` if it is not
- * defined in this scope.
- */
- LabelScope lookup(String targetLabel) {
- if (_label == targetLabel) {
- return this;
- } else if (_outerScope != null) {
- return _outerScope.lookup(targetLabel);
- } else {
- return null;
- }
- }
-}
-
-/**
- * Instances of the class `LibraryImportScope` represent the scope containing all of the names
- * available from imported libraries.
- */
-class LibraryImportScope extends Scope {
- /**
- * The element representing the library in which this scope is enclosed.
- */
- final LibraryElement _definingLibrary;
-
- /**
- * The listener that is to be informed when an error is encountered.
- */
- @override
- final AnalysisErrorListener errorListener;
-
- /**
- * A list of the namespaces representing the names that are available in this scope from imported
- * libraries.
- */
- List<Namespace> _importedNamespaces;
-
- /**
- * Initialize a newly created scope representing the names imported into the given library.
+ * Initialize a newly created visitor to resolve the nodes in an AST node.
*
- * @param definingLibrary the element representing the library that imports the names defined in
- * this scope
- * @param errorListener the listener that is to be informed when an error is encountered
+ * The [definingLibrary] is the element for the library containing the node
+ * being visited. The [source] is the source representing the compilation unit
+ * containing the node being visited. The [typeProvider] is the object used to
+ * access the types from the core library. The [errorListener] is the error
+ * listener that will be informed of any errors that are found during
+ * resolution. The [nameScope] is the scope used to resolve identifiers in the
+ * node that will first be visited. If `null` or unspecified, a new
+ * [LibraryScope] will be created based on the [definingLibrary].
*/
- LibraryImportScope(this._definingLibrary, this.errorListener) {
- _createImportedNamespaces();
- }
+ InstanceFieldResolverVisitor(LibraryElement definingLibrary, Source source,
+ TypeProvider typeProvider, AnalysisErrorListener errorListener,
+ {Scope nameScope})
+ : super(definingLibrary, source, typeProvider, errorListener,
+ nameScope: nameScope);
- @override
- void define(Element element) {
- if (!Scope.isPrivateName(element.displayName)) {
- super.define(element);
- }
- }
-
- @override
- Source getSource(AstNode node) {
- Source source = super.getSource(node);
- if (source == null) {
- source = _definingLibrary.definingCompilationUnit.source;
- }
- return source;
- }
-
- @override
- Element internalLookup(
- Identifier identifier, String name, LibraryElement referencingLibrary) {
- Element foundElement = localLookup(name, referencingLibrary);
- if (foundElement != null) {
- return foundElement;
- }
- for (int i = 0; i < _importedNamespaces.length; i++) {
- Namespace nameSpace = _importedNamespaces[i];
- Element element = nameSpace.get(name);
- if (element != null) {
- if (foundElement == null) {
- foundElement = element;
- } else if (!identical(foundElement, element)) {
- foundElement = MultiplyDefinedElementImpl.fromElements(
- _definingLibrary.context, foundElement, element);
+ /**
+ * Resolve the instance fields in the given compilation unit [node].
+ */
+ void resolveCompilationUnit(CompilationUnit node) {
+ _overrideManager.enterScope();
+ try {
+ NodeList<CompilationUnitMember> declarations = node.declarations;
+ int declarationCount = declarations.length;
+ for (int i = 0; i < declarationCount; i++) {
+ CompilationUnitMember declaration = declarations[i];
+ if (declaration is ClassDeclaration) {
+ _resolveClassDeclaration(declaration);
}
}
- }
- if (foundElement is MultiplyDefinedElementImpl) {
- foundElement = _removeSdkElements(
- identifier, name, foundElement as MultiplyDefinedElementImpl);
- }
- if (foundElement is MultiplyDefinedElementImpl) {
- String foundEltName = foundElement.displayName;
- List<Element> conflictingMembers = foundElement.conflictingElements;
- int count = conflictingMembers.length;
- List<String> libraryNames = new List<String>(count);
- for (int i = 0; i < count; i++) {
- libraryNames[i] = _getLibraryName(conflictingMembers[i]);
- }
- libraryNames.sort();
- errorListener.onError(new AnalysisError(
- getSource(identifier),
- identifier.offset,
- identifier.length,
- StaticWarningCode.AMBIGUOUS_IMPORT, [
- foundEltName,
- StringUtilities.printListOfQuotedNames(libraryNames)
- ]));
- return foundElement;
- }
- if (foundElement != null) {
- defineNameWithoutChecking(name, foundElement);
- }
- return foundElement;
- }
-
- /**
- * Create all of the namespaces associated with the libraries imported into this library. The
- * names are not added to this scope, but are stored for later reference.
- *
- * @param definingLibrary the element representing the library that imports the libraries for
- * which namespaces will be created
- */
- void _createImportedNamespaces() {
- NamespaceBuilder builder = new NamespaceBuilder();
- List<ImportElement> imports = _definingLibrary.imports;
- int count = imports.length;
- _importedNamespaces = new List<Namespace>(count);
- for (int i = 0; i < count; i++) {
- _importedNamespaces[i] =
- builder.createImportNamespaceForDirective(imports[i]);
+ } finally {
+ _overrideManager.exitScope();
}
}
/**
- * Returns the name of the library that defines given element.
- *
- * @param element the element to get library name
- * @return the name of the library that defines given element
+ * Resolve the instance fields in the given class declaration [node].
*/
- String _getLibraryName(Element element) {
- if (element == null) {
- return StringUtilities.EMPTY;
- }
- LibraryElement library = element.library;
- if (library == null) {
- return StringUtilities.EMPTY;
- }
- List<ImportElement> imports = _definingLibrary.imports;
- int count = imports.length;
- for (int i = 0; i < count; i++) {
- if (identical(imports[i].importedLibrary, library)) {
- return library.definingCompilationUnit.displayName;
- }
- }
- List<String> indirectSources = new List<String>();
- for (int i = 0; i < count; i++) {
- LibraryElement importedLibrary = imports[i].importedLibrary;
- if (importedLibrary != null) {
- for (LibraryElement exportedLibrary
- in importedLibrary.exportedLibraries) {
- if (identical(exportedLibrary, library)) {
- indirectSources
- .add(importedLibrary.definingCompilationUnit.displayName);
+ void _resolveClassDeclaration(ClassDeclaration node) {
+ _enclosingClassDeclaration = node;
+ ClassElement outerType = enclosingClass;
+ Scope outerScope = nameScope;
+ try {
+ enclosingClass = node.element;
+ typeAnalyzer.thisType = enclosingClass?.type;
+ if (enclosingClass == null) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Missing element for class declaration ${node.name.name} in ${definingLibrary.source.fullName}",
+ new CaughtException(new AnalysisException(), null));
+ // Don't try to re-resolve the initializers if we cannot set up the
+ // right name scope for resolution.
+ } else {
+ nameScope = new ClassScope(nameScope, enclosingClass);
+ NodeList<ClassMember> members = node.members;
+ int length = members.length;
+ for (int i = 0; i < length; i++) {
+ ClassMember member = members[i];
+ if (member is FieldDeclaration) {
+ _resolveFieldDeclaration(member);
}
}
}
- }
- int indirectCount = indirectSources.length;
- StringBuffer buffer = new StringBuffer();
- buffer.write(library.definingCompilationUnit.displayName);
- if (indirectCount > 0) {
- buffer.write(" (via ");
- if (indirectCount > 1) {
- indirectSources.sort();
- buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
- } else {
- buffer.write(indirectSources[0]);
- }
- buffer.write(")");
- }
- return buffer.toString();
- }
-
- /**
- * Given a collection of elements (captured by the [foundElement]) that the
- * [identifier] (with the given [name]) resolved to, remove from the list all
- * of the names defined in the SDK and return the element(s) that remain.
- */
- Element _removeSdkElements(Identifier identifier, String name,
- MultiplyDefinedElementImpl foundElement) {
- List<Element> conflictingElements = foundElement.conflictingElements;
- List<Element> nonSdkElements = new List<Element>();
- Element sdkElement = null;
- for (Element member in conflictingElements) {
- if (member.library.isInSdk) {
- sdkElement = member;
- } else {
- nonSdkElements.add(member);
- }
- }
- if (sdkElement != null && nonSdkElements.length > 0) {
- String sdkLibName = _getLibraryName(sdkElement);
- String otherLibName = _getLibraryName(nonSdkElements[0]);
- errorListener.onError(new AnalysisError(
- getSource(identifier),
- identifier.offset,
- identifier.length,
- StaticWarningCode.CONFLICTING_DART_IMPORT,
- [name, sdkLibName, otherLibName]));
- }
- if (nonSdkElements.length == conflictingElements.length) {
- // None of the members were removed
- return foundElement;
- } else if (nonSdkElements.length == 1) {
- // All but one member was removed
- return nonSdkElements[0];
- } else if (nonSdkElements.length == 0) {
- // All members were removed
- AnalysisEngine.instance.logger
- .logInformation("Multiply defined SDK element: $foundElement");
- return foundElement;
- }
- return new MultiplyDefinedElementImpl(
- _definingLibrary.context, nonSdkElements);
- }
-}
-
-/**
- * Instances of the class `LibraryScope` implement a scope containing all of the names defined
- * in a given library.
- */
-class LibraryScope extends EnclosedScope {
- /**
- * Initialize a newly created scope representing the names defined in the given library.
- *
- * @param definingLibrary the element representing the library represented by this scope
- * @param errorListener the listener that is to be informed when an error is encountered
- */
- LibraryScope(
- LibraryElement definingLibrary, AnalysisErrorListener errorListener)
- : super(new LibraryImportScope(definingLibrary, errorListener)) {
- _defineTopLevelNames(definingLibrary);
- }
-
- @override
- AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
- if (existing is PrefixElement) {
- // TODO(scheglov) consider providing actual 'nameOffset' from the
- // synthetic accessor
- int offset = duplicate.nameOffset;
- if (duplicate is PropertyAccessorElement) {
- PropertyAccessorElement accessor = duplicate;
- if (accessor.isSynthetic) {
- offset = accessor.variable.nameOffset;
- }
- }
- return new AnalysisError(
- duplicate.source,
- offset,
- duplicate.nameLength,
- CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
- [existing.displayName]);
- }
- return super.getErrorForDuplicate(existing, duplicate);
- }
-
- /**
- * Add to this scope all of the public top-level names that are defined in the given compilation
- * unit.
- *
- * @param compilationUnit the compilation unit defining the top-level names to be added to this
- * scope
- */
- void _defineLocalNames(CompilationUnitElement compilationUnit) {
- for (PropertyAccessorElement element in compilationUnit.accessors) {
- define(element);
- }
- for (ClassElement element in compilationUnit.enums) {
- define(element);
- }
- for (FunctionElement element in compilationUnit.functions) {
- define(element);
- }
- for (FunctionTypeAliasElement element
- in compilationUnit.functionTypeAliases) {
- define(element);
- }
- for (ClassElement element in compilationUnit.types) {
- define(element);
- }
- }
-
- /**
- * Add to this scope all of the names that are explicitly defined in the given library.
- *
- * @param definingLibrary the element representing the library that defines the names in this
- * scope
- */
- void _defineTopLevelNames(LibraryElement definingLibrary) {
- for (PrefixElement prefix in definingLibrary.prefixes) {
- define(prefix);
- }
- _defineLocalNames(definingLibrary.definingCompilationUnit);
- for (CompilationUnitElement compilationUnit in definingLibrary.parts) {
- _defineLocalNames(compilationUnit);
- }
- }
-}
-
-/**
- * This class is used to replace uses of `HashMap<String, ExecutableElement>`
- * which are not as performant as this class.
- */
-class MemberMap {
- /**
- * The current size of this map.
- */
- int _size = 0;
-
- /**
- * The array of keys.
- */
- List<String> _keys;
-
- /**
- * The array of ExecutableElement values.
- */
- List<ExecutableElement> _values;
-
- /**
- * Initialize a newly created member map to have the given [initialCapacity].
- * The map will grow if needed.
- */
- MemberMap([int initialCapacity = 10]) {
- _initArrays(initialCapacity);
- }
-
- /**
- * Initialize a newly created member map to contain the same members as the
- * given [memberMap].
- */
- MemberMap.from(MemberMap memberMap) {
- _initArrays(memberMap._size + 5);
- for (int i = 0; i < memberMap._size; i++) {
- _keys[i] = memberMap._keys[i];
- _values[i] = memberMap._values[i];
- }
- _size = memberMap._size;
- }
-
- /**
- * The size of the map.
- *
- * @return the size of the map.
- */
- int get size => _size;
-
- /**
- * Given some key, return the ExecutableElement value from the map, if the key does not exist in
- * the map, `null` is returned.
- *
- * @param key some key to look up in the map
- * @return the associated ExecutableElement value from the map, if the key does not exist in the
- * map, `null` is returned
- */
- ExecutableElement get(String key) {
- for (int i = 0; i < _size; i++) {
- if (_keys[i] != null && _keys[i] == key) {
- return _values[i];
- }
- }
- return null;
- }
-
- /**
- * Get and return the key at the specified location. If the key/value pair has been removed from
- * the set, then `null` is returned.
- *
- * @param i some non-zero value less than size
- * @return the key at the passed index
- * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than
- * zero or greater than or equal to the capacity of the arrays
- */
- String getKey(int i) => _keys[i];
-
- /**
- * Get and return the ExecutableElement at the specified location. If the key/value pair has been
- * removed from the set, then then `null` is returned.
- *
- * @param i some non-zero value less than size
- * @return the key at the passed index
- * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than
- * zero or greater than or equal to the capacity of the arrays
- */
- ExecutableElement getValue(int i) => _values[i];
-
- /**
- * Given some key/value pair, store the pair in the map. If the key exists already, then the new
- * value overrides the old value.
- *
- * @param key the key to store in the map
- * @param value the ExecutableElement value to store in the map
- */
- void put(String key, ExecutableElement value) {
- // If we already have a value with this key, override the value
- for (int i = 0; i < _size; i++) {
- if (_keys[i] != null && _keys[i] == key) {
- _values[i] = value;
- return;
- }
- }
- // If needed, double the size of our arrays and copy values over in both
- // arrays
- if (_size == _keys.length) {
- int newArrayLength = _size * 2;
- List<String> keys_new_array = new List<String>(newArrayLength);
- List<ExecutableElement> values_new_array =
- new List<ExecutableElement>(newArrayLength);
- for (int i = 0; i < _size; i++) {
- keys_new_array[i] = _keys[i];
- }
- for (int i = 0; i < _size; i++) {
- values_new_array[i] = _values[i];
- }
- _keys = keys_new_array;
- _values = values_new_array;
- }
- // Put new value at end of array
- _keys[_size] = key;
- _values[_size] = value;
- _size++;
- }
-
- /**
- * Given some [String] key, this method replaces the associated key and value pair with
- * `null`. The size is not decremented with this call, instead it is expected that the users
- * check for `null`.
- *
- * @param key the key of the key/value pair to remove from the map
- */
- void remove(String key) {
- for (int i = 0; i < _size; i++) {
- if (_keys[i] == key) {
- _keys[i] = null;
- _values[i] = null;
- return;
- }
- }
- }
-
- /**
- * Sets the ExecutableElement at the specified location.
- *
- * @param i some non-zero value less than size
- * @param value the ExecutableElement value to store in the map
- */
- void setValue(int i, ExecutableElement value) {
- _values[i] = value;
- }
-
- /**
- * Initializes [keys] and [values].
- */
- void _initArrays(int initialCapacity) {
- _keys = new List<String>(initialCapacity);
- _values = new List<ExecutableElement>(initialCapacity);
- }
-}
-
-/**
- * Instances of the class `Namespace` implement a mapping of identifiers to the elements
- * represented by those identifiers. Namespaces are the building blocks for scopes.
- */
-class Namespace {
- /**
- * An empty namespace.
- */
- static Namespace EMPTY = new Namespace(new HashMap<String, Element>());
-
- /**
- * A table mapping names that are defined in this namespace to the element representing the thing
- * declared with that name.
- */
- final HashMap<String, Element> _definedNames;
-
- /**
- * Initialize a newly created namespace to have the given defined names.
- *
- * @param definedNames the mapping from names that are defined in this namespace to the
- * corresponding elements
- */
- Namespace(this._definedNames);
-
- /**
- * Return a table containing the same mappings as those defined by this namespace.
- *
- * @return a table containing the same mappings as those defined by this namespace
- */
- Map<String, Element> get definedNames => _definedNames;
-
- /**
- * Return the element in this namespace that is available to the containing scope using the given
- * name.
- *
- * @param name the name used to reference the
- * @return the element represented by the given identifier
- */
- Element get(String name) => _definedNames[name];
-}
-
-/**
- * Instances of the class `NamespaceBuilder` are used to build a `Namespace`. Namespace
- * builders are thread-safe and re-usable.
- */
-class NamespaceBuilder {
- /**
- * Create a namespace representing the export namespace of the given [ExportElement].
- *
- * @param element the export element whose export namespace is to be created
- * @return the export namespace that was created
- */
- Namespace createExportNamespaceForDirective(ExportElement element) {
- LibraryElement exportedLibrary = element.exportedLibrary;
- if (exportedLibrary == null) {
- //
- // The exported library will be null if the URI does not reference a valid
- // library.
- //
- return Namespace.EMPTY;
- }
- HashMap<String, Element> exportedNames = _getExportMapping(exportedLibrary);
- exportedNames = _applyCombinators(exportedNames, element.combinators);
- return new Namespace(exportedNames);
- }
-
- /**
- * Create a namespace representing the export namespace of the given library.
- *
- * @param library the library whose export namespace is to be created
- * @return the export namespace that was created
- */
- Namespace createExportNamespaceForLibrary(LibraryElement library) {
- HashMap<String, Element> exportedNames = _getExportMapping(library);
- return new Namespace(exportedNames);
- }
-
- /**
- * Create a namespace representing the import namespace of the given library.
- *
- * @param library the library whose import namespace is to be created
- * @return the import namespace that was created
- */
- Namespace createImportNamespaceForDirective(ImportElement element) {
- LibraryElement importedLibrary = element.importedLibrary;
- if (importedLibrary == null) {
- //
- // The imported library will be null if the URI does not reference a valid
- // library.
- //
- return Namespace.EMPTY;
- }
- HashMap<String, Element> exportedNames = _getExportMapping(importedLibrary);
- exportedNames = _applyCombinators(exportedNames, element.combinators);
- exportedNames = _applyPrefix(exportedNames, element.prefix);
- return new Namespace(exportedNames);
- }
-
- /**
- * Create a namespace representing the public namespace of the given library.
- *
- * @param library the library whose public namespace is to be created
- * @return the public namespace that was created
- */
- Namespace createPublicNamespaceForLibrary(LibraryElement library) {
- HashMap<String, Element> definedNames = new HashMap<String, Element>();
- _addPublicNames(definedNames, library.definingCompilationUnit);
- for (CompilationUnitElement compilationUnit in library.parts) {
- _addPublicNames(definedNames, compilationUnit);
- }
- return new Namespace(definedNames);
- }
-
- /**
- * Add all of the names in the given namespace to the given mapping table.
- *
- * @param definedNames the mapping table to which the names in the given namespace are to be added
- * @param namespace the namespace containing the names to be added to this namespace
- */
- void _addAllFromNamespace(
- Map<String, Element> definedNames, Namespace namespace) {
- if (namespace != null) {
- definedNames.addAll(namespace.definedNames);
- }
- }
-
- /**
- * Add the given element to the given mapping table if it has a publicly visible name.
- *
- * @param definedNames the mapping table to which the public name is to be added
- * @param element the element to be added
- */
- void _addIfPublic(Map<String, Element> definedNames, Element element) {
- String name = element.name;
- if (name != null && !Scope.isPrivateName(name)) {
- definedNames[name] = element;
- }
- }
-
- /**
- * Add to the given mapping table all of the public top-level names that are defined in the given
- * compilation unit.
- *
- * @param definedNames the mapping table to which the public names are to be added
- * @param compilationUnit the compilation unit defining the top-level names to be added to this
- * namespace
- */
- void _addPublicNames(Map<String, Element> definedNames,
- CompilationUnitElement compilationUnit) {
- for (PropertyAccessorElement element in compilationUnit.accessors) {
- _addIfPublic(definedNames, element);
- }
- for (ClassElement element in compilationUnit.enums) {
- _addIfPublic(definedNames, element);
- }
- for (FunctionElement element in compilationUnit.functions) {
- _addIfPublic(definedNames, element);
- }
- for (FunctionTypeAliasElement element
- in compilationUnit.functionTypeAliases) {
- _addIfPublic(definedNames, element);
- }
- for (ClassElement element in compilationUnit.types) {
- _addIfPublic(definedNames, element);
- }
- }
-
- /**
- * Apply the given combinators to all of the names in the given mapping table.
- *
- * @param definedNames the mapping table to which the namespace operations are to be applied
- * @param combinators the combinators to be applied
- */
- HashMap<String, Element> _applyCombinators(
- HashMap<String, Element> definedNames,
- List<NamespaceCombinator> combinators) {
- for (NamespaceCombinator combinator in combinators) {
- if (combinator is HideElementCombinator) {
- definedNames = _hide(definedNames, combinator.hiddenNames);
- } else if (combinator is ShowElementCombinator) {
- definedNames = _show(definedNames, combinator.shownNames);
- } else {
- // Internal error.
- AnalysisEngine.instance.logger
- .logError("Unknown type of combinator: ${combinator.runtimeType}");
- }
- }
- return definedNames;
- }
-
- /**
- * Apply the given prefix to all of the names in the table of defined names.
- *
- * @param definedNames the names that were defined before this operation
- * @param prefixElement the element defining the prefix to be added to the names
- */
- HashMap<String, Element> _applyPrefix(
- HashMap<String, Element> definedNames, PrefixElement prefixElement) {
- if (prefixElement != null) {
- String prefix = prefixElement.name;
- HashMap<String, Element> newNames = new HashMap<String, Element>();
- definedNames.forEach((String name, Element element) {
- newNames["$prefix.$name"] = element;
- });
- return newNames;
- } else {
- return definedNames;
- }
- }
-
- /**
- * Create a mapping table representing the export namespace of the given library.
- *
- * @param library the library whose public namespace is to be created
- * @param visitedElements a set of libraries that do not need to be visited when processing the
- * export directives of the given library because all of the names defined by them will
- * be added by another library
- * @return the mapping table that was created
- */
- HashMap<String, Element> _computeExportMapping(
- LibraryElement library, HashSet<LibraryElement> visitedElements) {
- visitedElements.add(library);
- try {
- HashMap<String, Element> definedNames = new HashMap<String, Element>();
- for (ExportElement element in library.exports) {
- LibraryElement exportedLibrary = element.exportedLibrary;
- if (exportedLibrary != null &&
- !visitedElements.contains(exportedLibrary)) {
- //
- // The exported library will be null if the URI does not reference a
- // valid library.
- //
- HashMap<String, Element> exportedNames =
- _computeExportMapping(exportedLibrary, visitedElements);
- exportedNames = _applyCombinators(exportedNames, element.combinators);
- definedNames.addAll(exportedNames);
- }
- }
- _addAllFromNamespace(
- definedNames,
- (library.context as InternalAnalysisContext)
- .getPublicNamespace(library));
- return definedNames;
} finally {
- visitedElements.remove(library);
+ nameScope = outerScope;
+ typeAnalyzer.thisType = outerType?.type;
+ enclosingClass = outerType;
+ _enclosingClassDeclaration = null;
}
}
- HashMap<String, Element> _getExportMapping(LibraryElement library) {
- if (library is LibraryElementImpl) {
- if (library.exportNamespace != null) {
- return library.exportNamespace.definedNames;
- } else {
- HashMap<String, Element> exportMapping =
- _computeExportMapping(library, new HashSet<LibraryElement>());
- library.exportNamespace = new Namespace(exportMapping);
- return exportMapping;
- }
- }
- return _computeExportMapping(library, new HashSet<LibraryElement>());
- }
-
/**
- * Return a new map of names which has all the names from [definedNames]
- * with exception of [hiddenNames].
+ * Resolve the instance fields in the given field declaration [node].
*/
- Map<String, Element> _hide(
- HashMap<String, Element> definedNames, List<String> hiddenNames) {
- HashMap<String, Element> newNames =
- new HashMap<String, Element>.from(definedNames);
- for (String name in hiddenNames) {
- newNames.remove(name);
- newNames.remove("$name=");
- }
- return newNames;
- }
-
- /**
- * Return a new map of names which has only [shownNames] from [definedNames].
- */
- HashMap<String, Element> _show(
- HashMap<String, Element> definedNames, List<String> shownNames) {
- HashMap<String, Element> newNames = new HashMap<String, Element>();
- for (String name in shownNames) {
- Element element = definedNames[name];
- if (element != null) {
- newNames[name] = element;
- }
- String setterName = "$name=";
- element = definedNames[setterName];
- if (element != null) {
- newNames[setterName] = element;
+ void _resolveFieldDeclaration(FieldDeclaration node) {
+ if (!node.isStatic) {
+ for (VariableDeclaration field in node.fields.variables) {
+ field.initializer?.accept(this);
}
}
- return newNames;
}
}
@@ -7434,13 +5453,6 @@
TypeSystem typeSystem;
/**
- * The class element representing the class containing the current node,
- * or `null` if the current node is not contained in a class.
- */
- @override
- ClassElement enclosingClass = null;
-
- /**
* The class declaration representing the class containing the current node, or `null` if
* the current node is not contained in a class.
*/
@@ -7596,20 +5608,15 @@
while (expression is ParenthesizedExpression) {
expression = (expression as ParenthesizedExpression).expression;
}
- if (expression is! SimpleIdentifier) {
- return null;
- }
- SimpleIdentifier identifier = expression as SimpleIdentifier;
- Element element = identifier.staticElement;
- if (element is! VariableElement) {
- return null;
- }
- ElementKind kind = element.kind;
- if (kind == ElementKind.LOCAL_VARIABLE) {
- return element as VariableElement;
- }
- if (kind == ElementKind.PARAMETER) {
- return element as VariableElement;
+ if (expression is SimpleIdentifier) {
+ Element element = expression.staticElement;
+ if (element is VariableElement) {
+ ElementKind kind = element.kind;
+ if (kind == ElementKind.LOCAL_VARIABLE ||
+ kind == ElementKind.PARAMETER) {
+ return element;
+ }
+ }
}
return null;
}
@@ -8080,16 +6087,6 @@
@override
Object visitCompilationUnit(CompilationUnit node) {
- //
- // TODO(brianwilkerson) The goal of the code below is to visit the
- // declarations in such an order that we can infer type information for
- // top-level variables before we visit references to them. This is better
- // than making no effort, but still doesn't completely satisfy that goal
- // (consider for example "final var a = b; final var b = 0;"; we'll infer a
- // type of 'int' for 'b', but not for 'a' because of the order of the
- // visits). Ideally we would create a dependency graph, but that would
- // require references to be resolved, which they are not.
- //
_overrideManager.enterScope();
try {
NodeList<Directive> directives = node.directives;
@@ -8100,16 +6097,7 @@
NodeList<CompilationUnitMember> declarations = node.declarations;
int declarationCount = declarations.length;
for (int i = 0; i < declarationCount; i++) {
- CompilationUnitMember declaration = declarations[i];
- if (declaration is! ClassDeclaration) {
- declaration.accept(this);
- }
- }
- for (int i = 0; i < declarationCount; i++) {
- CompilationUnitMember declaration = declarations[i];
- if (declaration is ClassDeclaration) {
- declaration.accept(this);
- }
+ declarations[i].accept(this);
}
} finally {
_overrideManager.exitScope();
@@ -8518,7 +6506,7 @@
Expression condition = node.condition;
condition?.accept(this);
Map<VariableElement, DartType> thenOverrides =
- new HashMap<VariableElement, DartType>();
+ const <VariableElement, DartType>{};
Statement thenStatement = node.thenStatement;
if (thenStatement != null) {
_overrideManager.enterScope();
@@ -8542,7 +6530,7 @@
}
}
Map<VariableElement, DartType> elseOverrides =
- new HashMap<VariableElement, DartType>();
+ const <VariableElement, DartType>{};
Statement elseStatement = node.elseStatement;
if (elseStatement != null) {
_overrideManager.enterScope();
@@ -8567,7 +6555,7 @@
_overrideManager.applyOverrides(elseOverrides);
} else if (!thenIsAbrupt && !elseIsAbrupt) {
List<Map<VariableElement, DartType>> perBranchOverrides =
- new List<Map<VariableElement, DartType>>();
+ <Map<VariableElement, DartType>>[];
perBranchOverrides.add(thenOverrides);
perBranchOverrides.add(elseOverrides);
_overrideManager.mergeOverrides(perBranchOverrides);
@@ -8864,7 +6852,7 @@
@override
visitVariableDeclarationList(VariableDeclarationList node) {
for (VariableDeclaration decl in node.variables) {
- InferenceContext.setType(decl, node.type?.type);
+ InferenceContext.setType(decl, decl.element?.type);
}
super.visitVariableDeclarationList(node);
}
@@ -9010,18 +6998,16 @@
DartType _getIteratorElementType(Expression iteratorExpression) {
DartType expressionType = iteratorExpression.bestType;
if (expressionType is InterfaceType) {
- InterfaceType interfaceType = expressionType;
PropertyAccessorElement iteratorFunction =
- interfaceType.lookUpInheritedGetter("iterator");
+ expressionType.lookUpInheritedGetter("iterator");
if (iteratorFunction == null) {
// TODO(brianwilkerson) Should we report this error?
return null;
}
DartType iteratorType = iteratorFunction.returnType;
if (iteratorType is InterfaceType) {
- InterfaceType iteratorInterfaceType = iteratorType;
PropertyAccessorElement currentFunction =
- iteratorInterfaceType.lookUpInheritedGetter("current");
+ iteratorType.lookUpInheritedGetter("current");
if (currentFunction == null) {
// TODO(brianwilkerson) Should we report this error?
return null;
@@ -9285,18 +7271,16 @@
*/
void _promoteTypes(Expression condition) {
if (condition is BinaryExpression) {
- BinaryExpression binary = condition;
- if (binary.operator.type == TokenType.AMPERSAND_AMPERSAND) {
- Expression left = binary.leftOperand;
- Expression right = binary.rightOperand;
+ if (condition.operator.type == TokenType.AMPERSAND_AMPERSAND) {
+ Expression left = condition.leftOperand;
+ Expression right = condition.rightOperand;
_promoteTypes(left);
_promoteTypes(right);
_clearTypePromotionsIfPotentiallyMutatedIn(right);
}
} else if (condition is IsExpression) {
- IsExpression is2 = condition;
- if (is2.notOperator == null) {
- _promote(is2.expression, is2.type.type);
+ if (condition.notOperator == null) {
+ _promote(condition.expression, condition.type.type);
}
} else if (condition is ParenthesizedExpression) {
_promoteTypes(condition.expression);
@@ -9311,23 +7295,21 @@
*/
void _propagateFalseState(Expression condition) {
if (condition is BinaryExpression) {
- BinaryExpression binary = condition;
- if (binary.operator.type == TokenType.BAR_BAR) {
- _propagateFalseState(binary.leftOperand);
- _propagateFalseState(binary.rightOperand);
+ if (condition.operator.type == TokenType.BAR_BAR) {
+ _propagateFalseState(condition.leftOperand);
+ _propagateFalseState(condition.rightOperand);
}
} else if (condition is IsExpression) {
- IsExpression is2 = condition;
- if (is2.notOperator != null) {
+ if (condition.notOperator != null) {
// Since an is-statement doesn't actually change the type, we don't
// let it affect the propagated type when it would result in a loss
// of precision.
- overrideExpression(is2.expression, is2.type.type, false, false);
+ overrideExpression(
+ condition.expression, condition.type.type, false, false);
}
} else if (condition is PrefixExpression) {
- PrefixExpression prefix = condition;
- if (prefix.operator.type == TokenType.BANG) {
- _propagateTrueState(prefix.operand);
+ if (condition.operator.type == TokenType.BANG) {
+ _propagateTrueState(condition.operand);
}
} else if (condition is ParenthesizedExpression) {
_propagateFalseState(condition.expression);
@@ -9352,23 +7334,21 @@
*/
void _propagateTrueState(Expression condition) {
if (condition is BinaryExpression) {
- BinaryExpression binary = condition;
- if (binary.operator.type == TokenType.AMPERSAND_AMPERSAND) {
- _propagateTrueState(binary.leftOperand);
- _propagateTrueState(binary.rightOperand);
+ if (condition.operator.type == TokenType.AMPERSAND_AMPERSAND) {
+ _propagateTrueState(condition.leftOperand);
+ _propagateTrueState(condition.rightOperand);
}
} else if (condition is IsExpression) {
- IsExpression is2 = condition;
- if (is2.notOperator == null) {
+ if (condition.notOperator == null) {
// Since an is-statement doesn't actually change the type, we don't
// let it affect the propagated type when it would result in a loss
// of precision.
- overrideExpression(is2.expression, is2.type.type, false, false);
+ overrideExpression(
+ condition.expression, condition.type.type, false, false);
}
} else if (condition is PrefixExpression) {
- PrefixExpression prefix = condition;
- if (prefix.operator.type == TokenType.BANG) {
- _propagateFalseState(prefix.operand);
+ if (condition.operator.type == TokenType.BANG) {
+ _propagateFalseState(condition.operand);
}
} else if (condition is ParenthesizedExpression) {
_propagateTrueState(condition.expression);
@@ -9394,38 +7374,42 @@
List<ParameterElement> parameters,
void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
{bool reportAsError: false}) {
- List<ParameterElement> requiredParameters = new List<ParameterElement>();
- List<ParameterElement> positionalParameters = new List<ParameterElement>();
- HashMap<String, ParameterElement> namedParameters =
- new HashMap<String, ParameterElement>();
+ if (parameters.isEmpty && argumentList.arguments.isEmpty) {
+ return const <ParameterElement>[];
+ }
+ int requiredParameterCount = 0;
+ int unnamedParameterCount = 0;
+ List<ParameterElement> unnamedParameters = new List<ParameterElement>();
+ HashMap<String, ParameterElement> namedParameters = null;
for (ParameterElement parameter in parameters) {
ParameterKind kind = parameter.parameterKind;
if (kind == ParameterKind.REQUIRED) {
- requiredParameters.add(parameter);
+ unnamedParameters.add(parameter);
+ unnamedParameterCount++;
+ requiredParameterCount++;
} else if (kind == ParameterKind.POSITIONAL) {
- positionalParameters.add(parameter);
+ unnamedParameters.add(parameter);
+ unnamedParameterCount++;
} else {
+ namedParameters ??= new HashMap<String, ParameterElement>();
namedParameters[parameter.name] = parameter;
}
}
- List<ParameterElement> unnamedParameters =
- new List<ParameterElement>.from(requiredParameters);
- unnamedParameters.addAll(positionalParameters);
- int unnamedParameterCount = unnamedParameters.length;
int unnamedIndex = 0;
NodeList<Expression> arguments = argumentList.arguments;
int argumentCount = arguments.length;
List<ParameterElement> resolvedParameters =
new List<ParameterElement>(argumentCount);
int positionalArgumentCount = 0;
- HashSet<String> usedNames = new HashSet<String>();
+ HashSet<String> usedNames = null;
bool noBlankArguments = true;
for (int i = 0; i < argumentCount; i++) {
Expression argument = arguments[i];
if (argument is NamedExpression) {
SimpleIdentifier nameNode = argument.name.label;
String name = nameNode.name;
- ParameterElement element = namedParameters[name];
+ ParameterElement element =
+ namedParameters != null ? namedParameters[name] : null;
if (element == null) {
ErrorCode errorCode = (reportAsError
? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
@@ -9437,6 +7421,7 @@
resolvedParameters[i] = element;
nameNode.staticElement = element;
}
+ usedNames ??= new HashSet<String>();
if (!usedNames.add(name)) {
if (onError != null) {
onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode,
@@ -9453,14 +7438,13 @@
}
}
}
- if (positionalArgumentCount < requiredParameters.length &&
- noBlankArguments) {
+ if (positionalArgumentCount < requiredParameterCount && noBlankArguments) {
ErrorCode errorCode = (reportAsError
? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
: StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
if (onError != null) {
onError(errorCode, argumentList,
- [requiredParameters.length, positionalArgumentCount]);
+ [requiredParameterCount, positionalArgumentCount]);
}
} else if (positionalArgumentCount > unnamedParameterCount &&
noBlankArguments) {
@@ -9477,200 +7461,6 @@
}
/**
- * The abstract class `Scope` defines the behavior common to name scopes used by the resolver
- * to determine which names are visible at any given point in the code.
- */
-abstract class Scope {
- /**
- * The prefix used to mark an identifier as being private to its library.
- */
- static int PRIVATE_NAME_PREFIX = 0x5F;
-
- /**
- * The suffix added to the declared name of a setter when looking up the setter. Used to
- * disambiguate between a getter and a setter that have the same name.
- */
- static String SETTER_SUFFIX = "=";
-
- /**
- * The name used to look up the method used to implement the unary minus operator. Used to
- * disambiguate between the unary and binary operators.
- */
- static String UNARY_MINUS = "unary-";
-
- /**
- * A table mapping names that are defined in this scope to the element representing the thing
- * declared with that name.
- */
- HashMap<String, Element> _definedNames = new HashMap<String, Element>();
-
- /**
- * A flag indicating whether there are any names defined in this scope.
- */
- bool _hasName = false;
-
- /**
- * Return the scope in which this scope is lexically enclosed.
- *
- * @return the scope in which this scope is lexically enclosed
- */
- Scope get enclosingScope => null;
-
- /**
- * Return the listener that is to be informed when an error is encountered.
- *
- * @return the listener that is to be informed when an error is encountered
- */
- AnalysisErrorListener get errorListener;
-
- /**
- * Add the given element to this scope. If there is already an element with the given name defined
- * in this scope, then an error will be generated and the original element will continue to be
- * mapped to the name. If there is an element with the given name in an enclosing scope, then a
- * warning will be generated but the given element will hide the inherited element.
- *
- * @param element the element to be added to this scope
- */
- void define(Element element) {
- String name = _getName(element);
- if (name != null && !name.isEmpty) {
- if (_definedNames.containsKey(name)) {
- errorListener
- .onError(getErrorForDuplicate(_definedNames[name], element));
- } else {
- _definedNames[name] = element;
- _hasName = true;
- }
- }
- }
-
- /**
- * Add the given element to this scope without checking for duplication or hiding.
- *
- * @param name the name of the element to be added
- * @param element the element to be added to this scope
- */
- void defineNameWithoutChecking(String name, Element element) {
- _definedNames[name] = element;
- _hasName = true;
- }
-
- /**
- * Add the given element to this scope without checking for duplication or hiding.
- *
- * @param element the element to be added to this scope
- */
- void defineWithoutChecking(Element element) {
- _definedNames[_getName(element)] = element;
- _hasName = true;
- }
-
- /**
- * Return the error code to be used when reporting that a name being defined locally conflicts
- * with another element of the same name in the local scope.
- *
- * @param existing the first element to be declared with the conflicting name
- * @param duplicate another element declared with the conflicting name
- * @return the error code used to report duplicate names within a scope
- */
- AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
- // TODO(brianwilkerson) Customize the error message based on the types of
- // elements that share the same name.
- // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being
- // generated.
- Source source = duplicate.source;
- return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength,
- CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]);
- }
-
- /**
- * Return the source that contains the given identifier, or the source associated with this scope
- * if the source containing the identifier could not be determined.
- *
- * @param identifier the identifier whose source is to be returned
- * @return the source that contains the given identifier
- */
- Source getSource(AstNode node) {
- CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit);
- if (unit != null) {
- CompilationUnitElement unitElement = unit.element;
- if (unitElement != null) {
- return unitElement.source;
- }
- }
- return null;
- }
-
- /**
- * Return the element with which the given name is associated, or `null` if the name is not
- * defined within this scope.
- *
- * @param identifier the identifier node to lookup element for, used to report correct kind of a
- * problem and associate problem with
- * @param name the name associated with the element to be returned
- * @param referencingLibrary the library that contains the reference to the name, used to
- * implement library-level privacy
- * @return the element with which the given name is associated
- */
- Element internalLookup(
- Identifier identifier, String name, LibraryElement referencingLibrary);
-
- /**
- * Return the element with which the given name is associated, or `null` if the name is not
- * defined within this scope. This method only returns elements that are directly defined within
- * this scope, not elements that are defined in an enclosing scope.
- *
- * @param name the name associated with the element to be returned
- * @param referencingLibrary the library that contains the reference to the name, used to
- * implement library-level privacy
- * @return the element with which the given name is associated
- */
- Element localLookup(String name, LibraryElement referencingLibrary) {
- if (_hasName) {
- return _definedNames[name];
- }
- return null;
- }
-
- /**
- * Return the element with which the given identifier is associated, or `null` if the name
- * is not defined within this scope.
- *
- * @param identifier the identifier associated with the element to be returned
- * @param referencingLibrary the library that contains the reference to the name, used to
- * implement library-level privacy
- * @return the element with which the given identifier is associated
- */
- Element lookup(Identifier identifier, LibraryElement referencingLibrary) =>
- internalLookup(identifier, identifier.name, referencingLibrary);
-
- /**
- * Return the name that will be used to look up the given element.
- *
- * @param element the element whose look-up name is to be returned
- * @return the name that will be used to look up the given element
- */
- String _getName(Element element) {
- if (element is MethodElement) {
- MethodElement method = element;
- if (method.name == "-" && method.parameters.length == 0) {
- return UNARY_MINUS;
- }
- }
- return element.name;
- }
-
- /**
- * Return `true` if the given name is a library-private name.
- *
- * @param name the name being tested
- * @return `true` if the given name is a library-private name
- */
- static bool isPrivateName(String name) =>
- name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX);
-}
-
-/**
* The abstract class `ScopedVisitor` maintains name and label scopes as an AST structure is
* being visited.
*/
@@ -10348,15 +8138,13 @@
for (int i = 0; i < statementCount; i++) {
Statement statement = statements[i];
if (statement is VariableDeclarationStatement) {
- VariableDeclarationStatement vds = statement;
- NodeList<VariableDeclaration> variables = vds.variables.variables;
+ NodeList<VariableDeclaration> variables = statement.variables.variables;
int variableCount = variables.length;
for (int j = 0; j < variableCount; j++) {
scope.hide(variables[j].element);
}
} else if (statement is FunctionDeclarationStatement) {
- FunctionDeclarationStatement fds = statement;
- scope.hide(fds.functionDeclaration.element);
+ scope.hide(statement.functionDeclaration.element);
}
}
}
@@ -10783,17 +8571,16 @@
* @return the overridden type of the given element
*/
DartType getType(Element element) {
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- DartType type = _overridenTypes[element];
- if (_overridenTypes.containsKey(element)) {
+ Element nonAccessor =
+ element is PropertyAccessorElement ? element.variable : element;
+ DartType type = _overridenTypes[nonAccessor];
+ if (_overridenTypes.containsKey(nonAccessor)) {
return type;
}
if (type != null) {
return type;
} else if (_outerScope != null) {
- return _outerScope.getType(element);
+ return _outerScope.getType(nonAccessor);
}
return null;
}
@@ -10817,37 +8604,6 @@
}
/**
- * Instances of the class `TypeParameterScope` implement the scope defined by the type
- * parameters in a class.
- */
-class TypeParameterScope extends EnclosedScope {
- /**
- * 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 represented by this scope
- */
- TypeParameterScope(Scope enclosingScope, ClassElement typeElement)
- : super(enclosingScope) {
- if (typeElement == null) {
- throw new IllegalArgumentException("class element cannot be null");
- }
- _defineTypeParameters(typeElement);
- }
-
- /**
- * Define the type parameters for the class.
- *
- * @param typeElement the element representing the type represented by this scope
- */
- void _defineTypeParameters(ClassElement typeElement) {
- for (TypeParameterElement typeParameter in typeElement.typeParameters) {
- define(typeParameter);
- }
- }
-}
-
-/**
* Instances of the class `TypePromotionManager` manage the ability to promote types of local
* variables and formal parameters from their declared types based on control flow.
*/
@@ -11572,13 +9328,20 @@
@override
void visitClassMembersInScope(ClassDeclaration node) {
+ node.documentationComment?.accept(this);
+ node.metadata.accept(this);
//
// Process field declarations before constructors and methods so that the
// types of field formal parameters can be correctly resolved.
//
List<ClassMember> nonFields = new List<ClassMember>();
- node.visitChildren(
- new _TypeResolverVisitor_visitClassMembersInScope(this, nonFields));
+ for (ClassMember member in node.members) {
+ if (member is ConstructorDeclaration) {
+ nonFields.add(member);
+ } else {
+ member.accept(this);
+ }
+ }
int count = nonFields.length;
for (int i = 0; i < count; i++) {
nonFields[i].accept(this);
@@ -11651,7 +9414,6 @@
super.visitFieldFormalParameter(node);
Element element = node.identifier.staticElement;
if (element is ParameterElementImpl) {
- ParameterElementImpl parameter = element;
FormalParameterList parameterList = node.parameters;
if (parameterList == null) {
DartType type;
@@ -11659,9 +9421,9 @@
if (typeName == null) {
element.hasImplicitType = true;
type = _dynamicType;
- if (parameter is FieldFormalParameterElement) {
+ if (element is FieldFormalParameterElement) {
FieldElement fieldElement =
- (parameter as FieldFormalParameterElement).field;
+ (element as FieldFormalParameterElement).field;
if (fieldElement != null) {
type = fieldElement.type;
}
@@ -11669,9 +9431,9 @@
} else {
type = _getType(typeName);
}
- parameter.type = type;
+ element.type = type;
} else {
- _setFunctionTypedParameterType(parameter, node.type, node.parameters);
+ _setFunctionTypedParameterType(element, node.type, node.parameters);
}
} else {
// TODO(brianwilkerson) Report this internal error
@@ -11772,8 +9534,8 @@
declaredType = _getType(typeName);
}
Element element = node.identifier.staticElement;
- if (element is ParameterElement) {
- (element as ParameterElementImpl).type = declaredType;
+ if (element is ParameterElementImpl) {
+ element.type = declaredType;
} else {
// TODO(brianwilkerson) Report the internal error.
}
@@ -11836,8 +9598,9 @@
SimpleIdentifier prefix = prefixedIdentifier.prefix;
element = nameScope.lookup(prefix, definingLibrary);
if (element is PrefixElement) {
- if (parent.parent is InstanceCreationExpression &&
- (parent.parent as InstanceCreationExpression).isConst) {
+ AstNode grandParent = parent.parent;
+ if (grandParent is InstanceCreationExpression &&
+ grandParent.isConst) {
// If, if this is a const expression, then generate a
// CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
reportErrorForNode(
@@ -12066,13 +9829,12 @@
if (element is VariableElement) {
(element as VariableElementImpl).type = declaredType;
if (element is PropertyInducingElement) {
- PropertyInducingElement variableElement = element;
PropertyAccessorElementImpl getter =
- variableElement.getter as PropertyAccessorElementImpl;
+ element.getter as PropertyAccessorElementImpl;
getter.returnType = declaredType;
getter.type = new FunctionTypeImpl(getter);
PropertyAccessorElementImpl setter =
- variableElement.setter as PropertyAccessorElementImpl;
+ element.setter as PropertyAccessorElementImpl;
if (setter != null) {
List<ParameterElement> parameters = setter.parameters;
if (parameters.length > 0) {
@@ -12119,12 +9881,12 @@
return null;
}
Element element = identifier.staticElement;
- if (element is! ClassElementImpl) {
- // TODO(brianwilkerson) Report this
- // Internal error: Failed to create an element for a class declaration.
- return null;
+ if (element is ClassElementImpl) {
+ return element;
}
- return element as ClassElementImpl;
+ // TODO(brianwilkerson) Report this
+ // Internal error: Failed to create an element for a class declaration.
+ return null;
}
/**
@@ -12181,11 +9943,10 @@
RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
AstNode parent = typeName.parent;
if (parent is ConstructorName) {
- ConstructorName constructorName = parent as ConstructorName;
- parent = constructorName.parent;
- if (parent is ConstructorDeclaration) {
- if (identical(parent.redirectedConstructor, constructorName)) {
- if (parent.constKeyword != null) {
+ AstNode grandParent = parent.parent;
+ if (grandParent is ConstructorDeclaration) {
+ if (identical(grandParent.redirectedConstructor, parent)) {
+ if (grandParent.constKeyword != null) {
return RedirectingConstructorKind.CONST;
}
return RedirectingConstructorKind.NORMAL;
@@ -12266,8 +10027,7 @@
bool _isTypeNameInAsExpression(TypeName typeName) {
AstNode parent = typeName.parent;
if (parent is AsExpression) {
- AsExpression asExpression = parent;
- return identical(asExpression.type, typeName);
+ return identical(parent.type, typeName);
}
return false;
}
@@ -12281,8 +10041,7 @@
bool _isTypeNameInCatchClause(TypeName typeName) {
AstNode parent = typeName.parent;
if (parent is CatchClause) {
- CatchClause catchClause = parent;
- return identical(catchClause.exceptionType, typeName);
+ return identical(parent.exceptionType, typeName);
}
return false;
}
@@ -12298,9 +10057,7 @@
AstNode parent = typeName.parent;
if (parent is ConstructorName &&
parent.parent is InstanceCreationExpression) {
- ConstructorName constructorName = parent;
- return constructorName != null &&
- identical(constructorName.type, typeName);
+ return parent != null && identical(parent.type, typeName);
}
return false;
}
@@ -12314,8 +10071,7 @@
bool _isTypeNameInIsExpression(TypeName typeName) {
AstNode parent = typeName.parent;
if (parent is IsExpression) {
- IsExpression isExpression = parent;
- return identical(isExpression.type, typeName);
+ return identical(parent.type, typeName);
}
return false;
}
@@ -12512,11 +10268,9 @@
AstNode parent = node.parent;
if (parent is VariableDeclarationList) {
return identical(parent.type, node);
- }
- if (parent is FieldFormalParameter) {
+ } else if (parent is FieldFormalParameter) {
return identical(parent.type, node);
- }
- if (parent is SimpleFormalParameter) {
+ } else if (parent is SimpleFormalParameter) {
return identical(parent.type, node);
}
return false;
@@ -13064,38 +10818,3 @@
return null;
}
}
-
-class _TypeResolverVisitor_visitClassMembersInScope
- extends UnifyingAstVisitor<Object> {
- final TypeResolverVisitor TypeResolverVisitor_this;
-
- List<ClassMember> nonFields;
-
- _TypeResolverVisitor_visitClassMembersInScope(
- this.TypeResolverVisitor_this, this.nonFields)
- : super();
-
- @override
- Object visitConstructorDeclaration(ConstructorDeclaration node) {
- nonFields.add(node);
- return null;
- }
-
- @override
- Object visitExtendsClause(ExtendsClause node) => null;
-
- @override
- Object visitImplementsClause(ImplementsClause node) => null;
-
- @override
- Object visitMethodDeclaration(MethodDeclaration node) {
- nonFields.add(node);
- return null;
- }
-
- @override
- Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
-
- @override
- Object visitWithClause(WithClause node) => null;
-}
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 27577b8..8e1abb2 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -10,8 +10,7 @@
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptions;
-import 'package:analyzer/src/generated/source.dart'
- show ContentCache, Source, UriKind;
+import 'package:analyzer/src/generated/source.dart' show Source;
/**
* A function used to create a new DartSdk with the given [options]. If the
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 0387905..65e8f95 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -217,6 +217,11 @@
}
/**
+ * The number of lines.
+ */
+ int get lineCount => _lineStarts.length;
+
+ /**
* Return the location information for the character at the given [offset].
*/
LineInfo_Location getLocation(int offset) {
@@ -258,7 +263,7 @@
* [lineNumber].
*/
int getOffsetOfLine(int lineNumber) {
- if (lineNumber < 0 || lineNumber >= _lineStarts.length) {
+ if (lineNumber < 0 || lineNumber >= lineCount) {
throw new ArgumentError('Invalid line number: $lineNumber');
}
return _lineStarts[lineNumber];
@@ -750,12 +755,10 @@
int get hashCode => 31 * offset + length;
@override
- bool operator ==(Object obj) {
- if (obj is! SourceRange) {
- return false;
- }
- SourceRange sourceRange = obj as SourceRange;
- return sourceRange.offset == offset && sourceRange.length == length;
+ bool operator ==(Object other) {
+ return other is SourceRange &&
+ other.offset == offset &&
+ other.length == length;
}
/**
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 811a048..5c9c740 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -11,7 +11,6 @@
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
export 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index f76cf73..7eb4a8b 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -617,9 +617,11 @@
*/
@override
Object visitListLiteral(ListLiteral node) {
- DartType staticType = _dynamicType;
TypeArgumentList typeArguments = node.typeArguments;
+
+ // If we have explicit arguments, use them
if (typeArguments != null) {
+ DartType staticType = _dynamicType;
NodeList<TypeName> arguments = typeArguments.arguments;
if (arguments != null && arguments.length == 1) {
TypeName argumentTypeName = arguments[0];
@@ -628,25 +630,47 @@
staticType = argumentType;
}
}
- } else if (_strongMode) {
+ _recordStaticType(
+ node, _typeProvider.listType.instantiate(<DartType>[staticType]));
+ return null;
+ }
+
+ // If there are no type arguments and we are in strong mode, try to infer
+ // some arguments.
+ if (_strongMode) {
DartType contextType = InferenceContext.getType(node);
+
+ // If we have a type from the context, use it.
if (contextType is InterfaceType &&
contextType.typeArguments.length == 1 &&
contextType.element == _typeProvider.listType.element) {
- staticType = contextType.typeArguments[0];
_resolver.inferenceContext.recordInference(node, contextType);
- } else if (node.elements.isNotEmpty) {
+ _recordStaticType(node, contextType);
+ return null;
+ }
+
+ // If we don't have a type from the context, try to infer from the
+ // elements
+ if (node.elements.isNotEmpty) {
// Infer the list type from the arguments.
- // TODO(jmesserly): record inference here?
- staticType =
+ DartType staticType =
node.elements.map((e) => e.staticType).reduce(_leastUpperBound);
if (staticType.isBottom) {
staticType = _dynamicType;
}
+ DartType listLiteralType =
+ _typeProvider.listType.instantiate(<DartType>[staticType]);
+ if (!staticType.isDynamic) {
+ _resolver.inferenceContext.recordInference(node, listLiteralType);
+ }
+ _recordStaticType(node, listLiteralType);
+ return null;
}
}
+
+ // If we have no type arguments and couldn't infer any, use dynamic.
_recordStaticType(
- node, _typeProvider.listType.instantiate(<DartType>[staticType]));
+ node, _typeProvider.listType.instantiate(<DartType>[_dynamicType]));
return null;
}
@@ -664,10 +688,12 @@
*/
@override
Object visitMapLiteral(MapLiteral node) {
- DartType staticKeyType = _dynamicType;
- DartType staticValueType = _dynamicType;
TypeArgumentList typeArguments = node.typeArguments;
+
+ // If we have type arguments, use them
if (typeArguments != null) {
+ DartType staticKeyType = _dynamicType;
+ DartType staticValueType = _dynamicType;
NodeList<TypeName> arguments = typeArguments.arguments;
if (arguments != null && arguments.length == 2) {
TypeName entryKeyTypeName = arguments[0];
@@ -681,20 +707,31 @@
staticValueType = entryValueType;
}
}
- } else if (_strongMode) {
+ _recordStaticType(
+ node,
+ _typeProvider.mapType
+ .instantiate(<DartType>[staticKeyType, staticValueType]));
+ return null;
+ }
+
+ // If we have no explicit type arguments, and we are in strong mode
+ // then try to infer type arguments.
+ if (_strongMode) {
DartType contextType = InferenceContext.getType(node);
+ // If we have a context type, use that for inference.
if (contextType is InterfaceType &&
contextType.typeArguments.length == 2 &&
contextType.element == _typeProvider.mapType.element) {
- staticKeyType = contextType.typeArguments[0] ?? staticKeyType;
- staticValueType = contextType.typeArguments[1] ?? staticValueType;
_resolver.inferenceContext.recordInference(node, contextType);
- } else if (node.entries.isNotEmpty) {
- // Infer the list type from the arguments.
- // TODO(jmesserly): record inference here?
- staticKeyType =
+ _recordStaticType(node, contextType);
+ return null;
+ }
+
+ // Otherwise, try to infer a type from the keys and values.
+ if (node.entries.isNotEmpty) {
+ DartType staticKeyType =
node.entries.map((e) => e.key.staticType).reduce(_leastUpperBound);
- staticValueType = node.entries
+ DartType staticValueType = node.entries
.map((e) => e.value.staticType)
.reduce(_leastUpperBound);
if (staticKeyType.isBottom) {
@@ -703,12 +740,21 @@
if (staticValueType.isBottom) {
staticValueType = _dynamicType;
}
+ DartType mapLiteralType = _typeProvider.mapType
+ .instantiate(<DartType>[staticKeyType, staticValueType]);
+ if (!(staticValueType.isDynamic && staticKeyType.isDynamic)) {
+ _resolver.inferenceContext.recordInference(node, mapLiteralType);
+ }
+ _recordStaticType(node, mapLiteralType);
+ return null;
}
}
+
+ // If no type arguments and no inference, use dynamic
_recordStaticType(
node,
_typeProvider.mapType
- .instantiate(<DartType>[staticKeyType, staticValueType]));
+ .instantiate(<DartType>[_dynamicType, _dynamicType]));
return null;
}
@@ -1471,8 +1517,7 @@
*/
DartType _computePropagatedReturnTypeOfFunction(FunctionBody body) {
if (body is ExpressionFunctionBody) {
- ExpressionFunctionBody expressionBody = body;
- return expressionBody.expression.bestType;
+ return body.expression.bestType;
}
if (body is BlockFunctionBody) {
_StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction visitor =
@@ -1712,16 +1757,13 @@
* Return the propagated type of the given [Element], or `null`.
*/
DartType _getPropertyPropagatedType(Element element, DartType currentType) {
- if (element is PropertyAccessorElement) {
- PropertyAccessorElement accessor = element;
- if (accessor.isGetter) {
- PropertyInducingElement variable = accessor.variable;
- DartType propagatedType = variable.propagatedType;
- if (currentType == null ||
- propagatedType != null &&
- propagatedType.isMoreSpecificThan(currentType)) {
- return propagatedType;
- }
+ if (element is PropertyAccessorElement && element.isGetter) {
+ PropertyInducingElement variable = element.variable;
+ DartType propagatedType = variable.propagatedType;
+ if (currentType == null ||
+ propagatedType != null &&
+ propagatedType.isMoreSpecificThan(currentType)) {
+ return propagatedType;
}
}
return currentType;
@@ -1878,12 +1920,13 @@
VariableDeclaration node, Expression initializer) {
if (initializer != null &&
(node.parent as VariableDeclarationList).type == null &&
- (node.element is LocalVariableElementImpl) &&
(initializer.staticType != null) &&
(!initializer.staticType.isBottom)) {
- LocalVariableElementImpl element = node.element;
- element.type = initializer.staticType;
- node.name.staticType = initializer.staticType;
+ VariableElement element = node.element;
+ if (element is LocalVariableElementImpl) {
+ element.type = initializer.staticType;
+ node.name.staticType = initializer.staticType;
+ }
}
}
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index bf2e130..64dadf2 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -480,8 +480,8 @@
@override
InterfaceType get stringType {
if (_stringType == null) {
- _stringType = ElementFactory.classElement2("String").type;
- ClassElementImpl stringElement = _stringType.element as ClassElementImpl;
+ ClassElementImpl stringElement = ElementFactory.classElement2("String");
+ _stringType = stringElement.type;
_setAccessors(stringElement, <PropertyAccessorElement>[
ElementFactory.getterElement("isEmpty", false, boolType),
ElementFactory.getterElement("length", false, intType),
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 9caffef..526d067 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -29,6 +29,36 @@
@override
bool canPromoteToType(DartType to, DartType from) => isSubtypeOf(to, from);
+ @override
+ FunctionType functionTypeToConcreteType(
+ TypeProvider typeProvider, FunctionType t) {
+ // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function
+ // type? That would allow us to implement this in the subtype relation.
+ // TODO(jmesserly): we'll need to factor this differently if we want to
+ // move CodeChecker's functionality into existing analyzer. Likely we can
+ // let the Expression have a strict arrow, then in places were we do
+ // inference, convert back to a fuzzy arrow.
+
+ if (!t.parameters.any((p) => p.type.isDynamic)) {
+ return t;
+ }
+ ParameterElement shave(ParameterElement p) {
+ if (p.type.isDynamic) {
+ return new ParameterElementImpl.synthetic(
+ p.name, typeProvider.objectType, p.parameterKind);
+ }
+ return p;
+ }
+
+ List<ParameterElement> parameters = t.parameters.map(shave).toList();
+ FunctionElementImpl function = new FunctionElementImpl("", -1);
+ function.synthetic = true;
+ function.returnType = t.returnType;
+ function.shareTypeParameters(t.typeFormals);
+ function.shareParameters(parameters);
+ return function.type = new FunctionTypeImpl(function);
+ }
+
/**
* Given a type t, if t is an interface type with a call method
* defined, return the function type for the call method, otherwise
@@ -95,111 +125,6 @@
}
/**
- * This currently does not implement a very complete least upper bound
- * algorithm, but handles a couple of the very common cases that are
- * causing pain in real code. The current algorithm is:
- * 1. If either of the types is a supertype of the other, return it.
- * This is in fact the best result in this case.
- * 2. If the two types have the same class element, then take the
- * pointwise least upper bound of the type arguments. This is again
- * the best result, except that the recursive calls may not return
- * the true least uppper bounds. The result is guaranteed to be a
- * well-formed type under the assumption that the input types were
- * well-formed (and assuming that the recursive calls return
- * well-formed types).
- * 3. Otherwise return the spec-defined least upper bound. This will
- * be an upper bound, might (or might not) be least, and might
- * (or might not) be a well-formed type.
- *
- * TODO(leafp): Use matchTypes or something similar here to handle the
- * case where one of the types is a superclass (but not supertype) of
- * the other, e.g. LUB(Iterable<double>, List<int>) = Iterable<num>
- * TODO(leafp): Figure out the right final algorithm and implement it.
- */
- @override
- DartType _interfaceLeastUpperBound(
- TypeProvider provider, InterfaceType type1, InterfaceType type2) {
- if (isSubtypeOf(type1, type2)) {
- return type2;
- }
- if (isSubtypeOf(type2, type1)) {
- return type1;
- }
- if (type1.element == type2.element) {
- List<DartType> tArgs1 = type1.typeArguments;
- List<DartType> tArgs2 = type2.typeArguments;
-
- assert(tArgs1.length == tArgs2.length);
- List<DartType> tArgs = new List(tArgs1.length);
- for (int i = 0; i < tArgs1.length; i++) {
- tArgs[i] = getLeastUpperBound(provider, tArgs1[i], tArgs2[i]);
- }
- InterfaceTypeImpl lub = new InterfaceTypeImpl(type1.element);
- lub.typeArguments = tArgs;
- return lub;
- }
- return InterfaceTypeImpl.computeLeastUpperBound(type1, type2) ??
- provider.dynamicType;
- }
-
- /**
- * This currently just implements a simple least upper bound to
- * handle some common cases. It also avoids some termination issues
- * with the naive spec algorithm. The least upper bound of two types
- * (at least one of which is a type parameter) is computed here as:
- * 1. If either type is a supertype of the other, return it.
- * 2. If the first type is a type parameter, replace it with its bound,
- * with recursive occurrences of itself replaced with Object.
- * The second part of this should ensure termination. Informally,
- * each type variable instantiation in one of the arguments to the
- * least upper bound algorithm now strictly reduces the number
- * of bound variables in scope in that argument position.
- * 3. If the second type is a type parameter, do the symmetric operation
- * to #2.
- *
- * It's not immediately obvious why this is symmetric in the case that both
- * of the them are type parameters. For #1, symmetry holds since subtype
- * is antisymmetric. For #2, it's clearly not symmetric if upper bounds of
- * bottom are allowed. Ignoring this (for various reasons, not least
- * of which that there's no way to write it), there's an informal
- * argument (that might even be right) that you will always either
- * end up expanding both of them or else returning the same result no matter
- * which order you expand them in. A key observation is that
- * identical(expand(type1), type2) => subtype(type1, type2)
- * and hence the contra-positive.
- *
- * TODO(leafp): Think this through and figure out what's the right
- * definition. Be careful about termination.
- *
- * I suspect in general a reasonable algorithm is to expand the innermost
- * type variable first. Alternatively, you could probably choose to treat
- * it as just an instance of the interface type upper bound problem, with
- * the "inheritance" chain extended by the bounds placed on the variables.
- */
- @override
- DartType _typeParameterLeastUpperBound(
- TypeProvider provider, DartType type1, DartType type2) {
- if (isSubtypeOf(type1, type2)) {
- return type2;
- }
- if (isSubtypeOf(type2, type1)) {
- return type1;
- }
- if (type1 is TypeParameterType) {
- type1 = type1
- .resolveToBound(provider.objectType)
- .substitute2([provider.objectType], [type1]);
- return getLeastUpperBound(provider, type1, type2);
- }
- // We should only be called when at least one of the types is a
- // TypeParameterType
- type2 = type2
- .resolveToBound(provider.objectType)
- .substitute2([provider.objectType], [type2]);
- return getLeastUpperBound(provider, type1, type2);
- }
-
- /**
* Given a generic function type `F<T0, T1, ... Tn>` and a context type C,
* infer an instantiation of F, such that `F<S0, S1, ..., Sn>` <: C.
*
@@ -385,8 +310,12 @@
bool isGroundType(DartType t) {
// TODO(leafp): Revisit this.
- if (t is TypeParameterType) return false;
- if (_isTop(t)) return true;
+ if (t is TypeParameterType) {
+ return false;
+ }
+ if (_isTop(t)) {
+ return true;
+ }
if (t is FunctionType) {
if (!_isTop(t.returnType) ||
@@ -398,8 +327,8 @@
}
if (t is InterfaceType) {
- var typeArguments = t.typeArguments;
- for (var typeArgument in typeArguments) {
+ List<DartType> typeArguments = t.typeArguments;
+ for (DartType typeArgument in typeArguments) {
if (!_isTop(typeArgument)) return false;
}
return true;
@@ -417,6 +346,14 @@
return _isSubtypeOf(leftType, rightType, null);
}
+ @override
+ DartType typeToConcreteType(TypeProvider typeProvider, DartType t) {
+ if (t is FunctionType) {
+ return functionTypeToConcreteType(typeProvider, t);
+ }
+ return t;
+ }
+
/**
* Compute the greatest lower bound of function types [f] and [g].
*
@@ -561,6 +498,54 @@
return false;
}
+ /**
+ * This currently does not implement a very complete least upper bound
+ * algorithm, but handles a couple of the very common cases that are
+ * causing pain in real code. The current algorithm is:
+ * 1. If either of the types is a supertype of the other, return it.
+ * This is in fact the best result in this case.
+ * 2. If the two types have the same class element, then take the
+ * pointwise least upper bound of the type arguments. This is again
+ * the best result, except that the recursive calls may not return
+ * the true least uppper bounds. The result is guaranteed to be a
+ * well-formed type under the assumption that the input types were
+ * well-formed (and assuming that the recursive calls return
+ * well-formed types).
+ * 3. Otherwise return the spec-defined least upper bound. This will
+ * be an upper bound, might (or might not) be least, and might
+ * (or might not) be a well-formed type.
+ *
+ * TODO(leafp): Use matchTypes or something similar here to handle the
+ * case where one of the types is a superclass (but not supertype) of
+ * the other, e.g. LUB(Iterable<double>, List<int>) = Iterable<num>
+ * TODO(leafp): Figure out the right final algorithm and implement it.
+ */
+ @override
+ DartType _interfaceLeastUpperBound(
+ TypeProvider provider, InterfaceType type1, InterfaceType type2) {
+ if (isSubtypeOf(type1, type2)) {
+ return type2;
+ }
+ if (isSubtypeOf(type2, type1)) {
+ return type1;
+ }
+ if (type1.element == type2.element) {
+ List<DartType> tArgs1 = type1.typeArguments;
+ List<DartType> tArgs2 = type2.typeArguments;
+
+ assert(tArgs1.length == tArgs2.length);
+ List<DartType> tArgs = new List(tArgs1.length);
+ for (int i = 0; i < tArgs1.length; i++) {
+ tArgs[i] = getLeastUpperBound(provider, tArgs1[i], tArgs2[i]);
+ }
+ InterfaceTypeImpl lub = new InterfaceTypeImpl(type1.element);
+ lub.typeArguments = tArgs;
+ return lub;
+ }
+ return InterfaceTypeImpl.computeLeastUpperBound(type1, type2) ??
+ provider.dynamicType;
+ }
+
bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
return (t.isDynamic && dynamicIsBottom) || t.isBottom;
}
@@ -716,6 +701,63 @@
// TODO(leafp): Document the rules in play here
return (t.isDynamic && !dynamicIsBottom) || t.isObject;
}
+
+ /**
+ * This currently just implements a simple least upper bound to
+ * handle some common cases. It also avoids some termination issues
+ * with the naive spec algorithm. The least upper bound of two types
+ * (at least one of which is a type parameter) is computed here as:
+ * 1. If either type is a supertype of the other, return it.
+ * 2. If the first type is a type parameter, replace it with its bound,
+ * with recursive occurrences of itself replaced with Object.
+ * The second part of this should ensure termination. Informally,
+ * each type variable instantiation in one of the arguments to the
+ * least upper bound algorithm now strictly reduces the number
+ * of bound variables in scope in that argument position.
+ * 3. If the second type is a type parameter, do the symmetric operation
+ * to #2.
+ *
+ * It's not immediately obvious why this is symmetric in the case that both
+ * of the them are type parameters. For #1, symmetry holds since subtype
+ * is antisymmetric. For #2, it's clearly not symmetric if upper bounds of
+ * bottom are allowed. Ignoring this (for various reasons, not least
+ * of which that there's no way to write it), there's an informal
+ * argument (that might even be right) that you will always either
+ * end up expanding both of them or else returning the same result no matter
+ * which order you expand them in. A key observation is that
+ * identical(expand(type1), type2) => subtype(type1, type2)
+ * and hence the contra-positive.
+ *
+ * TODO(leafp): Think this through and figure out what's the right
+ * definition. Be careful about termination.
+ *
+ * I suspect in general a reasonable algorithm is to expand the innermost
+ * type variable first. Alternatively, you could probably choose to treat
+ * it as just an instance of the interface type upper bound problem, with
+ * the "inheritance" chain extended by the bounds placed on the variables.
+ */
+ @override
+ DartType _typeParameterLeastUpperBound(
+ TypeProvider provider, DartType type1, DartType type2) {
+ if (isSubtypeOf(type1, type2)) {
+ return type2;
+ }
+ if (isSubtypeOf(type2, type1)) {
+ return type1;
+ }
+ if (type1 is TypeParameterType) {
+ type1 = type1
+ .resolveToBound(provider.objectType)
+ .substitute2([provider.objectType], [type1]);
+ return getLeastUpperBound(provider, type1, type2);
+ }
+ // We should only be called when at least one of the types is a
+ // TypeParameterType
+ type2 = type2
+ .resolveToBound(provider.objectType)
+ .substitute2([provider.objectType], [type2]);
+ return getLeastUpperBound(provider, type1, type2);
+ }
}
/**
@@ -738,6 +780,25 @@
bool canPromoteToType(DartType to, DartType from);
/**
+ * Make a function type concrete.
+ *
+ * Normally we treat dynamically typed parameters as bottom for function
+ * types. This allows type tests such as `if (f is SingleArgFunction)`.
+ * It also requires a dynamic check on the parameter type to call these
+ * functions.
+ *
+ * When we convert to a strict arrow, dynamically typed parameters become
+ * top. This is safe to do for known functions, like top-level or local
+ * functions and static methods. Those functions must already be essentially
+ * treating dynamic as top.
+ *
+ * Only the outer-most arrow can be strict. Any others must be fuzzy, because
+ * we don't know what function value will be passed there.
+ */
+ FunctionType functionTypeToConcreteType(
+ TypeProvider typeProvider, FunctionType t);
+
+ /**
* Compute the least upper bound of two types.
*/
DartType getLeastUpperBound(
@@ -797,21 +858,6 @@
}
/**
- * Given two [InterfaceType]s [type1] and [type2] return their least upper
- * bound in a type system specific manner.
- */
- DartType _interfaceLeastUpperBound(
- TypeProvider provider, InterfaceType type1, InterfaceType type2);
-
- /**
- * Given two [DartType]s [type1] and [type2] at least one of which is a
- * [TypeParameterType], return their least upper bound in a type system
- * specific manner.
- */
- DartType _typeParameterLeastUpperBound(
- TypeProvider provider, DartType type1, DartType type2);
-
- /**
* Given a [DartType] [type], instantiate it with its bounds.
*
* The behavior of this method depends on the type system, for example, in
@@ -923,6 +969,14 @@
TypeParameterTypeImpl.getTypes(typeFormalsAsElements(type));
/**
+ * Make a type concrete. A type is concrete if it is not a function
+ * type, or if it is a function type with no dynamic parameters. A
+ * non-concrete function type is made concrete by replacing dynamic
+ * parameters with Object.
+ */
+ DartType typeToConcreteType(TypeProvider typeProvider, DartType t);
+
+ /**
* Compute the least upper bound of function types [f] and [g].
*
* The spec rules for LUB on function types, informally, are pretty simple
@@ -1005,6 +1059,21 @@
getLeastUpperBound(provider, f, g);
/**
+ * Given two [InterfaceType]s [type1] and [type2] return their least upper
+ * bound in a type system specific manner.
+ */
+ DartType _interfaceLeastUpperBound(
+ TypeProvider provider, InterfaceType type1, InterfaceType type2);
+
+ /**
+ * Given two [DartType]s [type1] and [type2] at least one of which is a
+ * [TypeParameterType], return their least upper bound in a type system
+ * specific manner.
+ */
+ DartType _typeParameterLeastUpperBound(
+ TypeProvider provider, DartType type1, DartType type2);
+
+ /**
* Create either a strong mode or regular type system based on context.
*/
static TypeSystem create(AnalysisContext context) {
@@ -1028,6 +1097,11 @@
return !from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from);
}
+ @override
+ FunctionType functionTypeToConcreteType(
+ TypeProvider typeProvider, FunctionType t) =>
+ t;
+
/**
* Instantiate a parameterized type using `dynamic` for all generic
* parameters. Returns the type unchanged if there are no parameters.
@@ -1058,6 +1132,9 @@
}
@override
+ DartType typeToConcreteType(TypeProvider typeProvider, DartType t) => t;
+
+ @override
DartType _interfaceLeastUpperBound(
TypeProvider provider, InterfaceType type1, InterfaceType type2) {
InterfaceType result =
diff --git a/pkg/analyzer/lib/src/summary/flat_buffers.dart b/pkg/analyzer/lib/src/summary/flat_buffers.dart
index 410d9d4..d573693 100644
--- a/pkg/analyzer/lib/src/summary/flat_buffers.dart
+++ b/pkg/analyzer/lib/src/summary/flat_buffers.dart
@@ -237,9 +237,11 @@
{
_currentVTable.computeFieldOffsets(tableTail);
// Try to find an existing compatible VTable.
- for (_VTable vTable in _vTables) {
+ for (int i = 0; i < _vTables.length; i++) {
+ _VTable vTable = _vTables[i];
if (_currentVTable.canUseExistingVTable(vTable)) {
vTableTail = vTable.tail;
+ break;
}
}
// Write a new VTable.
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index bd866c7..edaf034 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -1782,6 +1782,7 @@
*/
void flushInformative() {
_linkedLibraries?.forEach((b) => b.flushInformative());
+ _unlinkedUnitHashes = null;
_unlinkedUnits?.forEach((b) => b.flushInformative());
}
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index e7e548c..97528d7 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -147,7 +147,12 @@
/**
* The synthetic `values` getter of an enum.
*/
- enumValues
+ enumValues,
+
+ /**
+ * The containing unit itself.
+ */
+ unit
}
/**
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index ebbe533..d83c9ef 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -341,7 +341,12 @@
/**
* The synthetic `values` getter of an enum.
*/
- enumValues
+ enumValues,
+
+ /**
+ * The containing unit itself.
+ */
+ unit
}
/**
@@ -622,6 +627,7 @@
* is encoded as a hexadecimal string using lower case letters.
*/
@Id(4)
+ @informative
List<String> get unlinkedUnitHashes;
/**
diff --git a/pkg/analyzer/lib/src/summary/incremental_cache.dart b/pkg/analyzer/lib/src/summary/incremental_cache.dart
index 9900773..1d913be 100644
--- a/pkg/analyzer/lib/src/summary/incremental_cache.dart
+++ b/pkg/analyzer/lib/src/summary/incremental_cache.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 'dart:convert' show UTF8;
+import 'dart:convert' show ChunkedConversionSink, UTF8;
import 'dart:core' hide Resource;
import 'package:analyzer/dart/element/element.dart';
@@ -12,6 +12,7 @@
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
+import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
/**
@@ -242,7 +243,7 @@
*/
String _getCacheSourceContentKey(Source source) {
List<int> hash = _getSourceContentHash(source);
- String hashStr = CryptoUtils.bytesToHex(hash);
+ String hashStr = hex.encode(hash);
return '$hashStr.content';
}
@@ -267,7 +268,7 @@
*/
String _getLibraryBundleKey(Source librarySource) {
List<int> hash = _getLibraryClosureHash(librarySource);
- String hashStr = CryptoUtils.bytesToHex(hash);
+ String hashStr = hex.encode(hash);
return '$hashStr.summary';
}
@@ -291,13 +292,31 @@
List<int> _getLibraryClosureHash(Source librarySource) {
return _libraryClosureHashMap.putIfAbsent(librarySource, () {
List<Source> closure = _getLibraryClosure(librarySource);
- MD5 md5 = new MD5();
+
+ Digest digest;
+
+ var digestSink = new ChunkedConversionSink<Digest>.withCallback(
+ (List<Digest> digests) {
+ digest = digests.single;
+ });
+
+ var byteSink = md5.startChunkedConversion(digestSink);
+
for (Source source in closure) {
List<int> sourceHash = _getSourceContentHash(source);
- md5.add(sourceHash);
+ byteSink.add(sourceHash);
}
- md5.add(configSalt);
- return md5.close();
+ byteSink.add(configSalt);
+
+ byteSink.close();
+ // TODO(paulberry): this call to `close` should not be needed.
+ // Can be removed once
+ // https://github.com/dart-lang/crypto/issues/33
+ // is fixed – ensure the min version constraint on crypto is updated, tho.
+ // Does not cause any problems in the mean time.
+ digestSink.close();
+
+ return digest.bytes;
});
}
@@ -308,7 +327,7 @@
return _sourceContentHashMap.putIfAbsent(source, () {
String sourceText = source.contents.data;
List<int> sourceBytes = UTF8.encode(sourceText);
- return (new MD5()..add(sourceBytes)).close();
+ return md5.convert(sourceBytes).bytes;
});
}
diff --git a/pkg/analyzer/lib/src/summary/index_unit.dart b/pkg/analyzer/lib/src/summary/index_unit.dart
index 610fba4..bc09ee3 100644
--- a/pkg/analyzer/lib/src/summary/index_unit.dart
+++ b/pkg/analyzer/lib/src/summary/index_unit.dart
@@ -204,6 +204,7 @@
* This method is static, so it cannot add any information to the index.
*/
static ElementInfo newElementInfo(int unitId, Element element) {
+ int offset = null;
IndexSyntheticElementKind kind = IndexSyntheticElementKind.notSynthetic;
if (element.isSynthetic) {
if (element is ConstructorElement) {
@@ -242,11 +243,11 @@
throw new ArgumentError(
'Unsupported synthetic element ${element.runtimeType}');
}
- }
- int offset = element.nameOffset;
- if (element is LibraryElement || element is CompilationUnitElement) {
+ } else if (element is LibraryElement || element is CompilationUnitElement) {
+ kind = IndexSyntheticElementKind.unit;
offset = 0;
}
+ offset ??= element.nameOffset;
return new ElementInfo(unitId, offset, kind);
}
}
diff --git a/pkg/analyzer/lib/src/summary/inspect.dart b/pkg/analyzer/lib/src/summary/inspect.dart
new file mode 100644
index 0000000..799c15e
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/inspect.dart
@@ -0,0 +1,441 @@
+// Copyright (c) 2016, 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:convert';
+import 'dart:mirrors';
+
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/base.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+
+const int MAX_LINE_LENGTH = 80;
+
+/**
+ * Cache used to speed up [isEnum].
+ */
+Map<Type, bool> _isEnumCache = <Type, bool>{};
+
+/**
+ * Determine if the given [obj] has an enumerated type.
+ */
+bool isEnum(Object obj) {
+ return _isEnumCache.putIfAbsent(
+ obj.runtimeType, () => reflect(obj).type.isEnum);
+}
+
+/**
+ * Decoded reprensentation of a part of a summary that occupies multiple lines
+ * of output.
+ */
+class BrokenEntity implements DecodedEntity {
+ final String opener;
+ final Map<String, DecodedEntity> parts;
+ final String closer;
+
+ BrokenEntity(this.opener, this.parts, this.closer);
+
+ @override
+ List<String> getLines() {
+ List<String> result = <String>[opener];
+ bool first = true;
+ for (String key in parts.keys) {
+ if (first) {
+ first = false;
+ } else {
+ result[result.length - 1] += ',';
+ }
+ List<String> subResult = parts[key].getLines();
+ subResult[0] = '$key: ${subResult[0]}';
+ result.addAll(subResult.map((String s) => ' $s'));
+ }
+ result.add(closer);
+ return result;
+ }
+}
+
+/**
+ * Decoded representation of a part of a summary.
+ */
+abstract class DecodedEntity {
+ /**
+ * Create a representation of a part of the summary that consists of a group
+ * of entities (represented by [parts]) contained between [opener] and
+ * [closer].
+ *
+ * If [forceKeys] is `true`, the keys in [parts] will always be shown. If
+ * [forceKeys] is `false`, they keys will only be shown if the output is
+ * broken into multiple lines.
+ */
+ factory DecodedEntity.group(String opener, Map<String, DecodedEntity> parts,
+ String closer, bool forceKeys) {
+ // Attempt to format the entity in a single line; if not bail out and
+ // construct a _BrokenEntity.
+ DecodedEntity bailout() => new BrokenEntity(opener, parts, closer);
+ String short = opener;
+ bool first = true;
+ for (String key in parts.keys) {
+ if (first) {
+ first = false;
+ } else {
+ short += ', ';
+ }
+ DecodedEntity value = parts[key];
+ if (forceKeys) {
+ short += '$key: ';
+ }
+ if (value is UnbrokenEntity) {
+ short += value._s;
+ } else {
+ return bailout();
+ }
+ if (short.length > MAX_LINE_LENGTH) {
+ return bailout();
+ }
+ }
+ return new DecodedEntity.short(short + closer);
+ }
+
+ /**
+ * Create a representation of a part of the summary that is represented by a
+ * single unbroken string.
+ */
+ factory DecodedEntity.short(String s) = UnbrokenEntity;
+
+ /**
+ * Format this entity into a sequence of strings (one per output line).
+ */
+ List<String> getLines();
+}
+
+/**
+ * Wrapper around a [LinkedLibrary] and its constituent [UnlinkedUnit]s.
+ */
+class LibraryWrapper {
+ final LinkedLibrary _linked;
+ final List<UnlinkedUnit> _unlinked;
+
+ LibraryWrapper(this._linked, this._unlinked);
+}
+
+/**
+ * Wrapper around a [LinkedReference] and its corresponding [UnlinkedReference].
+ */
+class ReferenceWrapper {
+ final LinkedReference _linked;
+ final UnlinkedReference _unlinked;
+
+ ReferenceWrapper(this._linked, this._unlinked);
+
+ String get name {
+ if (_linked != null && _linked.name.isNotEmpty) {
+ return _linked.name;
+ } else if (_unlinked != null && _unlinked.name.isNotEmpty) {
+ return _unlinked.name;
+ } else {
+ return '???';
+ }
+ }
+}
+
+/**
+ * Instances of [SummaryInspector] are capable of traversing a summary and
+ * converting it to semi-human-readable output.
+ */
+class SummaryInspector {
+ /**
+ * The dependencies of the library currently being visited.
+ */
+ List<LinkedDependency> _dependencies;
+
+ /**
+ * The references of the unit currently being visited.
+ */
+ List<ReferenceWrapper> _references;
+
+ /**
+ * Indicates whether summary inspection should operate in "raw" mode. In this
+ * mode, the structure of the summary file is not altered for easier
+ * readability; everything is output in exactly the form in which it appears
+ * in the file.
+ */
+ final bool raw;
+
+ SummaryInspector(this.raw);
+
+ /**
+ * Decode the object [obj], which was reached by examining [key] inside
+ * another object.
+ */
+ DecodedEntity decode(Object obj, String key) {
+ if (!raw && obj is PackageBundle) {
+ return decodePackageBundle(obj);
+ }
+ if (obj is LibraryWrapper) {
+ return decodeLibrary(obj);
+ }
+ if (obj is UnitWrapper) {
+ return decodeUnit(obj);
+ }
+ if (obj is ReferenceWrapper) {
+ return decodeReference(obj);
+ }
+ if (obj is DecodedEntity) {
+ return obj;
+ }
+ if (obj is SummaryClass) {
+ Map<String, Object> map = obj.toMap();
+ return decodeMap(map);
+ } else if (obj is List) {
+ Map<String, DecodedEntity> parts = <String, DecodedEntity>{};
+ for (int i = 0; i < obj.length; i++) {
+ parts[i.toString()] = decode(obj[i], key);
+ }
+ return new DecodedEntity.group('[', parts, ']', false);
+ } else if (obj is String) {
+ return new DecodedEntity.short(JSON.encode(obj));
+ } else if (isEnum(obj)) {
+ return new DecodedEntity.short(obj.toString().split('.')[1]);
+ } else if (obj is int &&
+ key == 'dependency' &&
+ _dependencies != null &&
+ obj < _dependencies.length) {
+ return new DecodedEntity.short('$obj (${_dependencies[obj].uri})');
+ } else if (obj is int &&
+ key == 'reference' &&
+ _references != null &&
+ obj < _references.length) {
+ return new DecodedEntity.short('$obj (${_references[obj].name})');
+ } else {
+ return new DecodedEntity.short(obj.toString());
+ }
+ }
+
+ /**
+ * Decode the given [LibraryWrapper].
+ */
+ DecodedEntity decodeLibrary(LibraryWrapper obj) {
+ try {
+ LinkedLibrary linked = obj._linked;
+ List<UnlinkedUnit> unlinked = obj._unlinked;
+ _dependencies = linked.dependencies;
+ Map<String, Object> result = linked.toMap();
+ result.remove('units');
+ result['defining compilation unit'] =
+ new UnitWrapper(linked.units[0], unlinked[0]);
+ for (int i = 1; i < linked.units.length; i++) {
+ String partUri = unlinked[0].publicNamespace.parts[i - 1];
+ result['part ${JSON.encode(partUri)}'] =
+ new UnitWrapper(linked.units[i], unlinked[i]);
+ }
+ return decodeMap(result);
+ } finally {
+ _dependencies = null;
+ }
+ }
+
+ /**
+ * Decode the given [map].
+ */
+ DecodedEntity decodeMap(Map<String, Object> map) {
+ Map<String, DecodedEntity> parts = <String, DecodedEntity>{};
+ map = reorderMap(map);
+ map.forEach((String key, Object value) {
+ if (value is String && value.isEmpty) {
+ return;
+ }
+ if (isEnum(value) && (value as dynamic).index == 0) {
+ return;
+ }
+ if (value is int && value == 0) {
+ return;
+ }
+ if (value is bool && value == false) {
+ return;
+ }
+ if (value == null) {
+ return;
+ }
+ if (value is List) {
+ if (value.isEmpty) {
+ return;
+ }
+ DecodedEntity entity = decode(value, key);
+ if (entity is BrokenEntity) {
+ for (int i = 0; i < value.length; i++) {
+ parts['$key[$i]'] = decode(value[i], key);
+ }
+ return;
+ } else {
+ parts[key] = entity;
+ }
+ }
+ parts[key] = decode(value, key);
+ });
+ return new DecodedEntity.group('{', parts, '}', true);
+ }
+
+ /**
+ * Decode the given [PackageBundle].
+ */
+ DecodedEntity decodePackageBundle(PackageBundle bundle) {
+ Map<String, UnlinkedUnit> units = <String, UnlinkedUnit>{};
+ Set<String> seenUnits = new Set<String>();
+ for (int i = 0; i < bundle.unlinkedUnits.length; i++) {
+ units[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
+ }
+ Map<String, Object> restOfMap = bundle.toMap();
+ Map<String, Object> result = <String, Object>{};
+ result['version'] = new DecodedEntity.short(
+ '${bundle.majorVersion}.${bundle.minorVersion}');
+ restOfMap.remove('majorVersion');
+ restOfMap.remove('minorVersion');
+ result['linkedLibraryUris'] = restOfMap['linkedLibraryUris'];
+ result['unlinkedUnitUris'] = restOfMap['unlinkedUnitUris'];
+ for (int i = 0; i < bundle.linkedLibraries.length; i++) {
+ String libraryUriString = bundle.linkedLibraryUris[i];
+ Uri libraryUri = Uri.parse(libraryUriString);
+ UnlinkedUnit unlinkedDefiningUnit = units[libraryUriString];
+ seenUnits.add(libraryUriString);
+ List<UnlinkedUnit> libraryUnits = <UnlinkedUnit>[unlinkedDefiningUnit];
+ LinkedLibrary linkedLibrary = bundle.linkedLibraries[i];
+ for (int j = 1; j < linkedLibrary.units.length; j++) {
+ String partUriString = resolveRelativeUri(libraryUri,
+ Uri.parse(unlinkedDefiningUnit.publicNamespace.parts[j - 1]))
+ .toString();
+ libraryUnits.add(units[partUriString]);
+ seenUnits.add(partUriString);
+ }
+ result['library ${JSON.encode(libraryUriString)}'] =
+ new LibraryWrapper(linkedLibrary, libraryUnits);
+ }
+ for (String uriString in units.keys) {
+ if (seenUnits.contains(uriString)) {
+ continue;
+ }
+ result['orphan unit ${JSON.encode(uriString)}'] =
+ new UnitWrapper(null, units[uriString]);
+ }
+ restOfMap.remove('linkedLibraries');
+ restOfMap.remove('linkedLibraryUris');
+ restOfMap.remove('unlinkedUnits');
+ restOfMap.remove('unlinkedUnitUris');
+ result.addAll(restOfMap);
+ return decodeMap(result);
+ }
+
+ /**
+ * Decode the given [ReferenceWrapper].
+ */
+ DecodedEntity decodeReference(ReferenceWrapper obj) {
+ Map<String, Object> result = obj._unlinked != null
+ ? obj._unlinked.toMap()
+ : <String, Object>{'linkedOnly': true};
+ if (obj._linked != null) {
+ mergeMaps(result, obj._linked.toMap());
+ }
+ return decodeMap(result);
+ }
+
+ /**
+ * Decode the given [UnitWrapper].
+ */
+ DecodedEntity decodeUnit(UnitWrapper obj) {
+ try {
+ LinkedUnit linked = obj._linked;
+ UnlinkedUnit unlinked = obj._unlinked ?? new UnlinkedUnitBuilder();
+ Map<String, Object> unlinkedMap = unlinked.toMap();
+ Map<String, Object> linkedMap =
+ linked != null ? linked.toMap() : <String, Object>{};
+ Map<String, Object> result = <String, Object>{};
+ List<ReferenceWrapper> references = <ReferenceWrapper>[];
+ int numReferences = linked != null
+ ? linked.references.length
+ : unlinked.references.length;
+ for (int i = 0; i < numReferences; i++) {
+ references.add(new ReferenceWrapper(
+ linked != null ? linked.references[i] : null,
+ i < unlinked.references.length ? unlinked.references[i] : null));
+ }
+ result['references'] = references;
+ _references = references;
+ unlinkedMap.remove('references');
+ linkedMap.remove('references');
+ linkedMap.forEach((String key, Object value) {
+ result['linked $key'] = value;
+ });
+ unlinkedMap.forEach((String key, Object value) {
+ result[key] = value;
+ });
+ return decodeMap(result);
+ } finally {
+ _references = null;
+ }
+ }
+
+ /**
+ * Decode the given [PackageBundle] and dump it to a list of strings.
+ */
+ List<String> dumpPackageBundle(PackageBundle bundle) {
+ DecodedEntity decoded = decode(bundle, 'PackageBundle');
+ return decoded.getLines();
+ }
+
+ /**
+ * Merge the contents of [other] into [result], discarding empty entries.
+ */
+ void mergeMaps(Map<String, Object> result, Map<String, Object> other) {
+ other.forEach((String key, Object value) {
+ if (value is String && value.isEmpty) {
+ return;
+ }
+ if (result.containsKey(key)) {
+ Object oldValue = result[key];
+ if (oldValue is String && oldValue.isEmpty) {
+ result[key] = value;
+ } else {
+ throw new Exception(
+ 'Duplicate values for $key: $oldValue and $value');
+ }
+ } else {
+ result[key] = value;
+ }
+ });
+ }
+
+ /**
+ * Reorder [map] for more intuitive display.
+ */
+ Map<String, Object> reorderMap(Map<String, Object> map) {
+ Map<String, Object> result = <String, Object>{};
+ if (map.containsKey('name')) {
+ result['name'] = map['name'];
+ }
+ result.addAll(map);
+ return result;
+ }
+}
+
+/**
+ * Decoded reprensentation of a part of a summary that occupies a single line of
+ * output.
+ */
+class UnbrokenEntity implements DecodedEntity {
+ final String _s;
+
+ UnbrokenEntity(this._s);
+
+ @override
+ List<String> getLines() => <String>[_s];
+}
+
+/**
+ * Wrapper around a [LinkedUnit] and its corresponding [UnlinkedUnit].
+ */
+class UnitWrapper {
+ final LinkedUnit _linked;
+ final UnlinkedUnit _unlinked;
+
+ UnitWrapper(this._linked, this._unlinked);
+}
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 8d7d33e..0aff6d2 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -64,6 +64,8 @@
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/format.dart';
@@ -164,12 +166,8 @@
if (type is InterfaceType) {
ClassElementForLink element = type.element;
result.reference = compilationUnit.addReference(element);
- if (type.typeArguments.isNotEmpty) {
- result.typeArguments = type.typeArguments
- .map((DartType t) =>
- _createLinkedType(t, compilationUnit, typeParameterContext))
- .toList();
- }
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
return result;
} else if (type is DynamicTypeImpl) {
result.reference = compilationUnit.addRawReference('dynamic');
@@ -189,24 +187,22 @@
Element element = type.element;
if (element is FunctionElementForLink_FunctionTypedParam) {
result.reference =
- compilationUnit.addReference(element.enclosingExecutable);
+ compilationUnit.addReference(element.innermostExecutable);
result.implicitFunctionTypeIndices = element.implicitFunctionTypeIndices;
- if (type.typeArguments.isNotEmpty) {
- result.typeArguments = type.typeArguments
- .map((DartType t) =>
- _createLinkedType(t, compilationUnit, typeParameterContext))
- .toList();
- }
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
+ return result;
+ }
+ if (element is TopLevelFunctionElementForLink) {
+ result.reference = compilationUnit.addReference(element);
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
return result;
}
if (element is MethodElementForLink) {
result.reference = compilationUnit.addReference(element);
- if (type.typeArguments.isNotEmpty) {
- result.typeArguments = type.typeArguments
- .map((DartType t) =>
- _createLinkedType(t, compilationUnit, typeParameterContext))
- .toList();
- }
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
return result;
}
// TODO(paulberry): implement other cases.
@@ -217,6 +213,34 @@
}
/**
+ * Store the given [typeArguments] in [encodedType], using [compilationUnit] and
+ * [typeParameterContext] to serialize them.
+ *
+ * Trailing arguments of type `dynamic` are dropped.
+ */
+void _storeTypeArguments(
+ List<DartType> typeArguments,
+ EntityRefBuilder encodedType,
+ CompilationUnitElementInBuildUnit compilationUnit,
+ TypeParameterizedElementForLink typeParameterContext) {
+ int count = typeArguments.length;
+ while (count > 0) {
+ if (typeArguments[count - 1].isDynamic) {
+ count--;
+ } else {
+ List<EntityRefBuilder> encodedTypeArguments =
+ new List<EntityRefBuilder>(count);
+ for (int i = 0; i < count; i++) {
+ encodedTypeArguments[i] = _createLinkedType(
+ typeArguments[i], compilationUnit, typeParameterContext);
+ }
+ encodedType.typeArguments = encodedTypeArguments;
+ break;
+ }
+ }
+}
+
+/**
* Type of the callback used by [link] and [relink] to request
* [LinkedLibrary] objects from other build units.
*/
@@ -419,6 +443,9 @@
}
@override
+ String get identifier => name;
+
+ @override
List<InterfaceType> get interfaces => _interfaces ??=
_unlinkedClass.interfaces.map(_computeInterfaceType).toList();
@@ -535,6 +562,9 @@
}
}
+ @override
+ String toString() => '$enclosingElement.$name';
+
/**
* Convert [typeRef] into an [InterfaceType].
*/
@@ -627,13 +657,17 @@
@override
void link(CompilationUnitElementInBuildUnit compilationUnit) {}
+
+ @override
+ String toString() => '$enclosingElement.$name';
}
/**
* Element representing a compilation unit resynthesized from a
* summary during linking.
*/
-abstract class CompilationUnitElementForLink implements CompilationUnitElement {
+abstract class CompilationUnitElementForLink
+ implements CompilationUnitElementImpl {
/**
* The unlinked representation of the compilation unit in the
* summary.
@@ -646,19 +680,24 @@
*/
final List<ReferenceableElementForLink> _references;
- List<ClassElementForLink_Class> _types;
+ /**
+ * The absolute URI of this compilation unit.
+ */
+ final String _absoluteUri;
+ List<ClassElementForLink_Class> _types;
Map<String, ReferenceableElementForLink> _containedNames;
List<TopLevelVariableElementForLink> _topLevelVariables;
List<ClassElementForLink_Enum> _enums;
+ List<TopLevelFunctionElementForLink> _functions;
/**
* Index of this unit in the list of units in the enclosing library.
*/
final int unitNum;
- CompilationUnitElementForLink(
- UnlinkedUnit unlinkedUnit, this.unitNum, int numReferences)
+ CompilationUnitElementForLink(UnlinkedUnit unlinkedUnit, this.unitNum,
+ int numReferences, this._absoluteUri)
: _references = new List<ReferenceableElementForLink>(numReferences),
_unlinkedUnit = unlinkedUnit;
@@ -676,6 +715,22 @@
return _enums;
}
+ @override
+ List<TopLevelFunctionElementForLink> get functions {
+ if (_functions == null) {
+ _functions = <TopLevelFunctionElementForLink>[];
+ for (UnlinkedExecutable executable in _unlinkedUnit.executables) {
+ if (executable.kind == UnlinkedExecutableKind.functionOrMethod) {
+ _functions.add(new TopLevelFunctionElementForLink(this, executable));
+ }
+ }
+ }
+ return _functions;
+ }
+
+ @override
+ String get identifier => _absoluteUri;
+
/**
* Indicates whether this compilation element is part of the build unit
* currently being linked.
@@ -743,6 +798,9 @@
for (TopLevelVariableElementForLink variable in topLevelVariables) {
_containedNames[variable.name] = variable;
}
+ for (TopLevelFunctionElementForLink function in functions) {
+ _containedNames[function.name] = function;
+ }
// TODO(paulberry): fill in other top level entities (typedefs
// and executables).
}
@@ -761,6 +819,9 @@
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ @override
+ String toString() => enclosingElement.toString();
+
/**
* Return the element referred to by the given [index] in
* [UnlinkedUnit.references]. If the reference is unresolved,
@@ -854,9 +915,14 @@
@override
final LibraryElementInBuildUnit enclosingElement;
- CompilationUnitElementInBuildUnit(this.enclosingElement,
- UnlinkedUnit unlinkedUnit, this._linkedUnit, int unitNum)
- : super(unlinkedUnit, unitNum, unlinkedUnit.references.length);
+ CompilationUnitElementInBuildUnit(
+ this.enclosingElement,
+ UnlinkedUnit unlinkedUnit,
+ this._linkedUnit,
+ int unitNum,
+ String absoluteUri)
+ : super(
+ unlinkedUnit, unitNum, unlinkedUnit.references.length, absoluteUri);
@override
bool get isInBuildUnit => true;
@@ -918,13 +984,13 @@
numTypeParameters: element.typeParameters.length,
unitNum: element.enclosingElement.unitNum);
} else if (element is ExecutableElementForLink) {
- // TODO(paulberry): will this code ever be executed for an executable
- // element that's not inside a class?
- assert(element.enclosingElement is ClassElementForLink_Class);
+ ClassElementForLink_Class enclosingClass = element.enclosingClass;
ReferenceKind kind;
switch (element._unlinkedExecutable.kind) {
case UnlinkedExecutableKind.functionOrMethod:
- kind = ReferenceKind.method;
+ kind = enclosingClass != null
+ ? ReferenceKind.method
+ : ReferenceKind.topLevelFunction;
break;
case UnlinkedExecutableKind.setter:
kind = ReferenceKind.propertyAccessor;
@@ -935,7 +1001,8 @@
}
return addRawReference(element.name,
numTypeParameters: element.typeParameters.length,
- containingReference: addReference(element.enclosingElement),
+ containingReference:
+ enclosingClass != null ? addReference(enclosingClass) : null,
kind: kind);
}
// TODO(paulberry): implement other cases
@@ -1020,10 +1087,15 @@
@override
final LibraryElementInDependency enclosingElement;
- CompilationUnitElementInDependency(this.enclosingElement,
- UnlinkedUnit unlinkedUnit, LinkedUnit linkedUnit, int unitNum)
+ CompilationUnitElementInDependency(
+ this.enclosingElement,
+ UnlinkedUnit unlinkedUnit,
+ LinkedUnit linkedUnit,
+ int unitNum,
+ String absoluteUri)
: _linkedUnit = linkedUnit,
- super(unlinkedUnit, unitNum, linkedUnit.references.length) {
+ super(
+ unlinkedUnit, unitNum, linkedUnit.references.length, absoluteUri) {
// Make one pass through the linked types to determine the lengths for
// _linkedTypeRefs and _linkedTypes. TODO(paulberry): add an int to the
// summary to make this unnecessary.
@@ -1115,7 +1187,7 @@
UnlinkedConstructorInitializerKind.thisInvocation) {
defaultSuperInvocationNeeded = false;
ConstructorElementForLink constructor = constructorElement
- .enclosingElement
+ .enclosingClass
.getContainedName(constructorInitializer.name)
.asConstructor;
safeAddDependency(constructor?._constNode);
@@ -1161,7 +1233,7 @@
EntityRef redirectedConstructor =
constructorElement._unlinkedExecutable.redirectedConstructor;
if (redirectedConstructor != null) {
- return constructorElement.enclosingElement.enclosingElement
+ return constructorElement.enclosingUnit
._resolveRef(redirectedConstructor.reference)
.asConstructor;
} else {
@@ -1283,10 +1355,11 @@
*/
ConstConstructorNode _constNode;
- ConstructorElementForLink(ClassElementForLink_Class enclosingElement,
+ ConstructorElementForLink(ClassElementForLink_Class enclosingClass,
UnlinkedExecutable unlinkedExecutable)
- : super(enclosingElement, unlinkedExecutable) {
- if (enclosingElement.enclosingElement.isInBuildUnit &&
+ : super(enclosingClass.enclosingElement, enclosingClass,
+ unlinkedExecutable) {
+ if (enclosingClass.enclosingElement.isInBuildUnit &&
_unlinkedExecutable != null &&
_unlinkedExecutable.constCycleSlot != 0) {
_constNode = new ConstConstructorNode(this);
@@ -1380,6 +1453,22 @@
}
/**
+ * Stub implementation of [AnalysisContext] which provides just those methods
+ * needed during linking.
+ */
+class ContextForLink implements AnalysisContext {
+ final Linker _linker;
+
+ ContextForLink(this._linker);
+
+ @override
+ TypeSystem get typeSystem => _linker.typeSystem;
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
* An instance of [DependencyWalker] contains the core algorithms for
* walking a dependency graph and evaluating nodes in a safe order.
*/
@@ -1510,7 +1599,7 @@
* linking.
*/
abstract class ExecutableElementForLink extends Object
- with TypeParameterizedElementForLink
+ with TypeParameterizedElementForLink, ParameterParentElementForLink
implements ExecutableElementImpl {
/**
* The unlinked representation of the method in the summary.
@@ -1522,30 +1611,92 @@
FunctionTypeImpl _type;
List<TypeParameterElementForLink> _typeParameters;
String _name;
- List<ParameterElementForLink> _parameters;
+ String _displayName;
/**
- * TODO(paulberry): this won't always be a class element.
+ * Return the class in which this executable appears, maybe `null` for a
+ * top-level function.
*/
- @override
- final ClassElementForLink_Class enclosingElement;
-
- ExecutableElementForLink(this.enclosingElement, this._unlinkedExecutable);
+ final ClassElementForLink_Class enclosingClass;
/**
* Return the compilation unit in which this executable appears.
*/
- CompilationUnitElementForLink get compilationUnit =>
- enclosingElement.enclosingElement;
+ final CompilationUnitElementForLink enclosingUnit;
+
+ ExecutableElementForLink(
+ this.enclosingUnit, this.enclosingClass, this._unlinkedExecutable);
+
+ /**
+ * If the executable element had an explicitly declared return type, return
+ * it. Otherwise return `null`.
+ */
+ DartType get declaredReturnType {
+ if (_unlinkedExecutable.returnType == null) {
+ return null;
+ } else {
+ return _declaredReturnType ??=
+ enclosingUnit._resolveTypeRef(_unlinkedExecutable.returnType, this);
+ }
+ }
+
+ @override
+ String get displayName {
+ if (_displayName == null) {
+ _displayName = _unlinkedExecutable.name;
+ if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
+ _displayName = _displayName.substring(0, _displayName.length - 1);
+ }
+ }
+ return _displayName;
+ }
+
+ @override
+ Element get enclosingElement => enclosingClass ?? enclosingUnit;
@override
TypeParameterizedElementForLink get enclosingTypeParameterContext =>
- enclosingElement;
+ enclosingClass;
@override
bool get hasImplicitReturnType => _unlinkedExecutable.returnType == null;
@override
+ List<int> get implicitFunctionTypeIndices => const <int>[];
+
+ /**
+ * Return the inferred return type of the executable element. Should only be
+ * called if no return type was explicitly declared.
+ */
+ DartType get inferredReturnType {
+ // We should only try to infer a return type when none is explicitly
+ // declared.
+ assert(_unlinkedExecutable.returnType == null);
+ if (Linker._initializerTypeInferenceCycle != null &&
+ Linker._initializerTypeInferenceCycle ==
+ enclosingUnit.library.libraryCycleForLink) {
+ // We are currently computing the type of an initializer expression in the
+ // current library cycle, so type inference results should be ignored.
+ return _computeDefaultReturnType();
+ }
+ if (_inferredReturnType == null) {
+ if (_unlinkedExecutable.kind == UnlinkedExecutableKind.constructor) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ } else if (enclosingUnit.isInBuildUnit) {
+ _inferredReturnType = _computeDefaultReturnType();
+ } else {
+ _inferredReturnType = enclosingUnit.getLinkedType(
+ _unlinkedExecutable.inferredReturnTypeSlot, this);
+ }
+ }
+ return _inferredReturnType;
+ }
+
+ @override
+ ExecutableElementForLink get innermostExecutable => this;
+
+ @override
bool get isStatic => _unlinkedExecutable.isStatic;
@override
@@ -1566,47 +1717,7 @@
}
@override
- List<ParameterElementForLink> get parameters {
- if (_parameters == null) {
- int numParameters = _unlinkedExecutable.parameters.length;
- _parameters = new List<ParameterElementForLink>(numParameters);
- for (int i = 0; i < numParameters; i++) {
- UnlinkedParam unlinkedParam = _unlinkedExecutable.parameters[i];
- _parameters[i] = new ParameterElementForLink(
- this, unlinkedParam, this, enclosingElement.enclosingElement, i);
- }
- }
- return _parameters;
- }
-
- @override
- DartType get returnType {
- if (_inferredReturnType != null) {
- return _inferredReturnType;
- } else if (_declaredReturnType == null) {
- if (_unlinkedExecutable.returnType == null) {
- if (_unlinkedExecutable.kind == UnlinkedExecutableKind.constructor) {
- // TODO(paulberry): implement.
- throw new UnimplementedError();
- } else if (!compilationUnit.isInBuildUnit) {
- _inferredReturnType = compilationUnit.getLinkedType(
- _unlinkedExecutable.inferredReturnTypeSlot, this);
- return _inferredReturnType;
- } else if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter &&
- library._linker.strongMode) {
- // In strong mode, setters without an explicit return type are
- // considered to return `void`.
- _declaredReturnType = VoidTypeImpl.instance;
- } else {
- _declaredReturnType = DynamicTypeImpl.instance;
- }
- } else {
- _declaredReturnType = enclosingElement.enclosingElement
- ._resolveTypeRef(_unlinkedExecutable.returnType, this);
- }
- }
- return _declaredReturnType;
- }
+ DartType get returnType => declaredReturnType ?? inferredReturnType;
@override
void set returnType(DartType inferredType) {
@@ -1618,6 +1729,9 @@
FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
@override
+ List<UnlinkedParam> get unlinkedParameters => _unlinkedExecutable.parameters;
+
+ @override
List<UnlinkedTypeParam> get _unlinkedTypeParams =>
_unlinkedExecutable.typeParameters;
@@ -1629,12 +1743,30 @@
* Store the results of type inference for this method in [compilationUnit].
*/
void link(CompilationUnitElementInBuildUnit compilationUnit) {
- compilationUnit._storeLinkedType(
- _unlinkedExecutable.inferredReturnTypeSlot, returnType, this);
+ if (_unlinkedExecutable.returnType == null) {
+ compilationUnit._storeLinkedType(
+ _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
+ }
for (ParameterElementForLink parameterElement in parameters) {
parameterElement.link(compilationUnit);
}
}
+
+ /**
+ * Compute the default return type for this type of executable element (if no
+ * return type is declared and strong mode type inference cannot infer a
+ * better return type).
+ */
+ DartType _computeDefaultReturnType() {
+ if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter &&
+ library._linker.strongMode) {
+ // In strong mode, setters without an explicit return type are
+ // considered to return `void`.
+ return VoidTypeImpl.instance;
+ } else {
+ return DynamicTypeImpl.instance;
+ }
+ }
}
class ExprTypeComputer {
@@ -1962,11 +2094,11 @@
// to infer the type of type arguments.
stack.length -= numNamed + numPositional;
strPtr += numNamed;
- EntityRef ref = unlinkedConst.references[refPtr++];
+ EntityRef ref = _getNextRef();
ConstructorElementForLink element =
unit._resolveRef(ref.reference).asConstructor;
if (element != null) {
- stack.add(element.enclosingElement.buildType(
+ stack.add(element.enclosingClass.buildType(
(int i) => i >= ref.typeArguments.length
? DynamicTypeImpl.instance
: unit._resolveTypeRef(
@@ -1983,50 +2115,18 @@
List<String> namedArgNames = _getNextStrings(numNamed);
List<DartType> namedArgTypeList = _popList(numNamed);
List<DartType> positionalArgTypes = _popList(numPositional);
+ // TODO(scheglov) if we pushed target and method name first, we might be
+ // able to move work with arguments in _inferExecutableType()
String methodName = _getNextString();
DartType target = stack.removeLast();
stack.add(() {
if (target is InterfaceType) {
MethodElement method = target.lookUpMethod(methodName, library);
- DartType rawMethodType = method?.type;
- TypeSystem ts = linker.typeSystem;
- if (rawMethodType is FunctionType) {
- if (rawMethodType.typeFormals.isNotEmpty &&
- ts is StrongTypeSystemImpl) {
- List<DartType> paramTypes = <DartType>[];
- List<DartType> argTypes = <DartType>[];
- // Add positional parameter and argument types.
- for (int i = 0; i < numPositional; i++) {
- ParameterElement parameter = rawMethodType.parameters[i];
- if (parameter != null) {
- paramTypes.add(parameter.type);
- argTypes.add(positionalArgTypes[i]);
- }
- }
- // Prepare named argument types map.
- Map<String, DartType> namedArgTypes = <String, DartType>{};
- for (int i = 0; i < numNamed; i++) {
- String name = namedArgNames[i];
- DartType type = namedArgTypeList[i];
- namedArgTypes[name] = type;
- }
- // Add named parameter and argument types.
- Map<String, DartType> namedParameterTypes =
- rawMethodType.namedParameterTypes;
- namedArgTypes.forEach((String name, DartType argType) {
- DartType parameterType = namedParameterTypes[name];
- if (parameterType != null) {
- paramTypes.add(parameterType);
- argTypes.add(argType);
- }
- });
- // Perform inference.
- FunctionType inferred = ts.inferGenericFunctionCall(
- typeProvider, rawMethodType, paramTypes, argTypes, null);
- return inferred.returnType;
- }
- // Not a generic method, use the raw return type.
- return rawMethodType.returnType;
+ FunctionType rawType = method?.type;
+ FunctionType inferredType = _inferExecutableType(rawType, numNamed,
+ numPositional, namedArgNames, namedArgTypeList, positionalArgTypes);
+ if (inferredType != null) {
+ return inferredType.returnType;
}
}
return DynamicTypeImpl.instance;
@@ -2036,13 +2136,22 @@
void _doInvokeMethodRef() {
int numNamed = _getNextInt();
int numPositional = _getNextInt();
- // TODO(paulberry): don't just pop the args; use their types
- // to infer the type of type arguments.
- stack.length -= numNamed + numPositional;
- strPtr += numNamed;
- refPtr++;
- // TODO(paulberry): implement.
- stack.add(DynamicTypeImpl.instance);
+ List<String> namedArgNames = _getNextStrings(numNamed);
+ List<DartType> namedArgTypeList = _popList(numNamed);
+ List<DartType> positionalArgTypes = _popList(numPositional);
+ EntityRef ref = _getNextRef();
+ ReferenceableElementForLink element = unit._resolveRef(ref.reference);
+ stack.add(() {
+ DartType rawType = element.asStaticType;
+ if (rawType is FunctionType) {
+ FunctionType inferredType = _inferExecutableType(rawType, numNamed,
+ numPositional, namedArgNames, namedArgTypeList, positionalArgTypes);
+ if (inferredType != null) {
+ return inferredType.returnType;
+ }
+ }
+ return DynamicTypeImpl.instance;
+ }());
}
void _doMakeTypedList() {
@@ -2087,7 +2196,7 @@
}
void _doPushReference() {
- EntityRef ref = unlinkedConst.references[refPtr++];
+ EntityRef ref = _getNextRef();
if (ref.paramReference != 0) {
stack.add(typeProvider.typeType);
} else {
@@ -2097,8 +2206,7 @@
// Nor can implicit function types derived from
// function-typed parameters.
assert(ref.implicitFunctionTypeIndices.isEmpty);
- ReferenceableElementForLink element =
- variable.compilationUnit._resolveRef(ref.reference);
+ ReferenceableElementForLink element = unit._resolveRef(ref.reference);
stack.add(element.asStaticType);
}
}
@@ -2107,6 +2215,8 @@
return unlinkedConst.ints[intPtr++];
}
+ EntityRef _getNextRef() => unlinkedConst.references[refPtr++];
+
String _getNextString() {
return unlinkedConst.strings[strPtr++];
}
@@ -2120,7 +2230,7 @@
}
DartType _getNextTypeRef() {
- EntityRef ref = unlinkedConst.references[refPtr++];
+ EntityRef ref = _getNextRef();
return unit._resolveTypeRef(ref, variable._typeParameterContext);
}
@@ -2135,6 +2245,53 @@
: DynamicTypeImpl.instance;
}
+ FunctionType _inferExecutableType(
+ FunctionType rawMethodType,
+ int numNamed,
+ int numPositional,
+ List<String> namedArgNames,
+ List<DartType> namedArgTypeList,
+ List<DartType> positionalArgTypes) {
+ TypeSystem ts = linker.typeSystem;
+ if (rawMethodType != null) {
+ if (rawMethodType.typeFormals.isNotEmpty && ts is StrongTypeSystemImpl) {
+ List<DartType> paramTypes = <DartType>[];
+ List<DartType> argTypes = <DartType>[];
+ // Add positional parameter and argument types.
+ for (int i = 0; i < numPositional; i++) {
+ ParameterElement parameter = rawMethodType.parameters[i];
+ if (parameter != null) {
+ paramTypes.add(parameter.type);
+ argTypes.add(positionalArgTypes[i]);
+ }
+ }
+ // Prepare named argument types map.
+ Map<String, DartType> namedArgTypes = <String, DartType>{};
+ for (int i = 0; i < numNamed; i++) {
+ String name = namedArgNames[i];
+ DartType type = namedArgTypeList[i];
+ namedArgTypes[name] = type;
+ }
+ // Add named parameter and argument types.
+ Map<String, DartType> namedParameterTypes =
+ rawMethodType.namedParameterTypes;
+ namedArgTypes.forEach((String name, DartType argType) {
+ DartType parameterType = namedParameterTypes[name];
+ if (parameterType != null) {
+ paramTypes.add(parameterType);
+ argTypes.add(argType);
+ }
+ });
+ // Perform inference.
+ FunctionType inferred = ts.inferGenericFunctionCall(
+ typeProvider, rawMethodType, paramTypes, argTypes, null);
+ return inferred;
+ }
+ }
+ // Not a generic function type, use the raw type.
+ return rawMethodType;
+ }
+
DartType _leastUpperBound(DartType s, DartType t) {
return linker.typeSystem.getLeastUpperBound(typeProvider, s, t);
}
@@ -2264,12 +2421,10 @@
/**
* If this is an instance field, the type that was computed by
- * [InstanceMemberInferrer].
+ * [InstanceMemberInferrer] (if any). Otherwise `null`.
*/
DartType _inferredInstanceType;
- DartType _declaredType;
-
FieldElementForLink_ClassField(ClassElementForLink_Class enclosingElement,
UnlinkedVariable unlinkedVariable)
: enclosingElement = enclosingElement,
@@ -2279,29 +2434,6 @@
bool get isStatic => unlinkedVariable.isStatic;
@override
- DartType get type {
- // TODO(paulberry): can this be unified with
- // [VariableElementForLink.asStaticType]?
- assert(!isStatic);
- if (_inferredInstanceType != null) {
- return _inferredInstanceType;
- } else if (_declaredType == null) {
- if (unlinkedVariable.type == null) {
- if (!compilationUnit.isInBuildUnit) {
- _inferredInstanceType = compilationUnit.getLinkedType(
- unlinkedVariable.inferredTypeSlot, enclosingElement);
- return _inferredInstanceType;
- }
- _declaredType = DynamicTypeImpl.instance;
- } else {
- _declaredType = compilationUnit._resolveTypeRef(
- unlinkedVariable.type, enclosingElement);
- }
- }
- return _declaredType;
- }
-
- @override
void set type(DartType inferredType) {
assert(!isStatic);
assert(_inferredInstanceType == null);
@@ -2317,18 +2449,15 @@
*/
void link(CompilationUnitElementInBuildUnit compilationUnit) {
if (hasImplicitType) {
- if (isStatic) {
- TypeInferenceNode typeInferenceNode = this.asTypeInferenceNode;
- if (typeInferenceNode != null) {
- compilationUnit._storeLinkedType(unlinkedVariable.inferredTypeSlot,
- typeInferenceNode.inferredType, enclosingElement);
- }
- } else {
- compilationUnit._storeLinkedType(unlinkedVariable.inferredTypeSlot,
- _inferredInstanceType, enclosingElement);
- }
+ compilationUnit._storeLinkedType(
+ unlinkedVariable.inferredTypeSlot,
+ isStatic ? inferredType : _inferredInstanceType,
+ _typeParameterContext);
}
}
+
+ @override
+ String toString() => '$enclosingElement.$name';
}
/**
@@ -2385,32 +2514,43 @@
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
}
/**
* Element representing a function-typed parameter resynthesied from a summary
* during linking.
*/
-class FunctionElementForLink_FunctionTypedParam implements FunctionElement {
+class FunctionElementForLink_FunctionTypedParam extends Object
+ with ParameterParentElementForLink
+ implements FunctionElement {
@override
final ParameterElementForLink enclosingElement;
- /**
- * The executable element containing this function-typed parameter.
- */
- final Element enclosingExecutable;
+ @override
+ final ExecutableElementForLink innermostExecutable;
- /**
- * The appropriate integer list to store in
- * [EntityRef.implicitFunctionTypeIndices] to refer to this function-typed
- * parameter.
- */
- final List<int> implicitFunctionTypeIndices;
+ @override
+ final List<UnlinkedParam> unlinkedParameters;
DartType _returnType;
+ List<int> _implicitFunctionTypeIndices;
- FunctionElementForLink_FunctionTypedParam(this.enclosingElement,
- this.enclosingExecutable, this.implicitFunctionTypeIndices);
+ FunctionElementForLink_FunctionTypedParam(
+ this.enclosingElement, this.innermostExecutable, this.unlinkedParameters);
+
+ @override
+ List<int> get implicitFunctionTypeIndices {
+ if (_implicitFunctionTypeIndices == null) {
+ _implicitFunctionTypeIndices = enclosingElement
+ .enclosingElement.implicitFunctionTypeIndices
+ .toList();
+ _implicitFunctionTypeIndices.add(enclosingElement._parameterIndex);
+ }
+ return _implicitFunctionTypeIndices;
+ }
@override
DartType get returnType {
@@ -2419,8 +2559,7 @@
_returnType = DynamicTypeImpl.instance;
} else {
_returnType = enclosingElement.compilationUnit._resolveTypeRef(
- enclosingElement._unlinkedParam.type,
- enclosingElement._typeParameterContext);
+ enclosingElement._unlinkedParam.type, innermostExecutable);
}
}
return _returnType;
@@ -2447,9 +2586,8 @@
@override
DartType get returnType {
// If this is a variable whose type needs inferring, infer it.
- TypeInferenceNode typeInferenceNode = _variable._typeInferenceNode;
- if (typeInferenceNode != null) {
- return typeInferenceNode.inferredType;
+ if (_variable.hasImplicitType) {
+ return _variable.inferredType;
} else {
// There's no reason linking should need to access the type of
// this FunctionElement, since the variable doesn't need its
@@ -2462,7 +2600,8 @@
@override
void set returnType(DartType newType) {
- // TODO(paulberry): store inferred type.
+ // InstanceMemberInferrer stores the new type both here and on the variable
+ // element. We don't need to record both values, so we ignore it here.
}
@override
@@ -2592,7 +2731,7 @@
*/
abstract class LibraryElementForLink<
UnitElement extends CompilationUnitElementForLink>
- implements LibraryElement {
+ implements LibraryElementImpl {
/**
* Pointer back to the linker.
*/
@@ -2617,6 +2756,9 @@
}
}
+ @override
+ ContextForLink get context => _linker.context;
+
/**
* Get the [UnlinkedUnit] for the defining compilation unit of this library.
*/
@@ -2631,9 +2773,15 @@
_linkedLibrary.exportDependencies.map(_getDependency).toList();
@override
+ String get identifier => _absoluteUri.toString();
+
+ @override
List<LibraryElementForLink> get importedLibraries => _importedLibraries ??=
_linkedLibrary.importDependencies.map(_getDependency).toList();
+ @override
+ bool get isDartAsync => _absoluteUri == 'dart:async';
+
/**
* If this library is part of the build unit being linked, return the library
* cycle it is part of. Otherwise return `null`.
@@ -2644,17 +2792,20 @@
List<UnitElement> get units {
if (_units == null) {
UnlinkedUnit definingUnit = definingUnlinkedUnit;
- _units = <UnitElement>[_makeUnitElement(definingUnit, 0)];
+ _units = <UnitElement>[
+ _makeUnitElement(definingUnit, 0, _absoluteUri.toString())
+ ];
int numParts = definingUnit.parts.length;
for (int i = 0; i < numParts; i++) {
// TODO(paulberry): make sure we handle the case where Uri.parse fails.
// TODO(paulberry): make sure we handle the case where
// resolveRelativeUri fails.
- UnlinkedUnit partUnit = _linker.getUnit(resolveRelativeUri(
+ String partAbsoluteUri = resolveRelativeUri(
_absoluteUri, Uri.parse(definingUnit.publicNamespace.parts[i]))
- .toString());
- _units.add(
- _makeUnitElement(partUnit ?? new UnlinkedUnitBuilder(), i + 1));
+ .toString();
+ UnlinkedUnit partUnit = _linker.getUnit(partAbsoluteUri);
+ _units.add(_makeUnitElement(
+ partUnit ?? new UnlinkedUnitBuilder(), i + 1, partAbsoluteUri));
}
}
return _units;
@@ -2684,6 +2835,9 @@
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ @override
+ String toString() => _absoluteUri.toString();
+
/**
* Return the [LibraryElement] corresponding to the given dependency [index].
*/
@@ -2696,7 +2850,8 @@
* Create a [UnitElement] for one of the library's compilation
* units.
*/
- UnitElement _makeUnitElement(UnlinkedUnit unlinkedUnit, int i);
+ UnitElement _makeUnitElement(
+ UnlinkedUnit unlinkedUnit, int i, String absoluteUri);
}
/**
@@ -2777,9 +2932,9 @@
@override
CompilationUnitElementInBuildUnit _makeUnitElement(
- UnlinkedUnit unlinkedUnit, int i) =>
+ UnlinkedUnit unlinkedUnit, int i, String absoluteUri) =>
new CompilationUnitElementInBuildUnit(
- this, unlinkedUnit, _linkedLibrary.units[i], i);
+ this, unlinkedUnit, _linkedLibrary.units[i], i, absoluteUri);
}
/**
@@ -2800,9 +2955,9 @@
@override
CompilationUnitElementInDependency _makeUnitElement(
- UnlinkedUnit unlinkedUnit, int i) =>
+ UnlinkedUnit unlinkedUnit, int i, String absoluteUri) =>
new CompilationUnitElementInDependency(
- this, unlinkedUnit, _linkedLibrary.units[i], i);
+ this, unlinkedUnit, _linkedLibrary.units[i], i, absoluteUri);
}
/**
@@ -2851,6 +3006,17 @@
*/
class Linker {
/**
+ * During linking, if type inference is currently being performed on the
+ * initializer of a static or instance variable, the library cycle in
+ * which inference is being performed. Otherwise, `null`.
+ *
+ * This allows us to suppress instance member type inference results from a
+ * library cycle while doing inference on the right hand sides of static and
+ * instance variables in that same cycle.
+ */
+ static LibraryCycleForLink _initializerTypeInferenceCycle;
+
+ /**
* Callback to ask the client for a [LinkedLibrary] for a
* dependency.
*/
@@ -2888,6 +3054,7 @@
SpecialTypeElementForLink _voidElement;
SpecialTypeElementForLink _dynamicElement;
SpecialTypeElementForLink _bottomElement;
+ ContextForLink _context;
Linker(Map<String, LinkedLibraryBuilder> linkedLibraries, this.getDependency,
this.getUnit, this.strongMode) {
@@ -2914,6 +3081,12 @@
new SpecialTypeElementForLink(this, BottomTypeImpl.instance);
/**
+ * Get a stub implementation of [AnalysisContext] which can be used during
+ * linking.
+ */
+ get context => _context ??= new ContextForLink(this);
+
+ /**
* Get the library element for `dart:core`.
*/
LibraryElementForLink get coreLibrary =>
@@ -2979,15 +3152,22 @@
*/
class MethodElementForLink extends ExecutableElementForLink
implements MethodElementImpl {
- MethodElementForLink(ClassElementForLink_Class enclosingElement,
+ MethodElementForLink(ClassElementForLink_Class enclosingClass,
UnlinkedExecutable unlinkedExecutable)
- : super(enclosingElement, unlinkedExecutable);
+ : super(enclosingClass.enclosingElement, enclosingClass,
+ unlinkedExecutable);
+
+ @override
+ String get identifier => name;
@override
ElementKind get kind => ElementKind.METHOD;
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
}
/**
@@ -3030,18 +3210,23 @@
}
/**
- * Element used for references that result from trying to access a nonstatic
+ * Element used for references that result from trying to access a non-static
* member of an element that is not a container (e.g. accessing the "length"
* property of a constant).
*/
class NonstaticMemberElementForLink implements ReferenceableElementForLink {
/**
+ * The non-static element of this link element.
+ */
+ final Element element;
+
+ /**
* If the thing from which a member was accessed is a constant, the
* associated [ConstNode]. Otherwise `null`.
*/
final ConstVariableNode _constNode;
- NonstaticMemberElementForLink(this._constNode);
+ NonstaticMemberElementForLink(this.element, this._constNode);
@override
ConstructorElementForLink get asConstructor => null;
@@ -3051,7 +3236,16 @@
@override
DartType get asStaticType {
- // TODO(paulberry): implement.
+ Element element = this.element;
+ if (element is PropertyAccessorElement) {
+ if (element.isGetter) {
+ return element.returnType;
+ }
+ return DynamicTypeImpl.instance;
+ }
+ if (element is MethodElement) {
+ return element.type;
+ }
return DynamicTypeImpl.instance;
}
@@ -3067,7 +3261,17 @@
DynamicTypeImpl.instance;
@override
- ReferenceableElementForLink getContainedName(String name) => this;
+ ReferenceableElementForLink getContainedName(String name) {
+ if (element != null) {
+ DartType type = asStaticType;
+ if (type is InterfaceType) {
+ Element nameElement = type.lookUpGetter(name, element.library);
+ nameElement ??= type.lookUpMethod(name, element.library);
+ return new NonstaticMemberElementForLink(nameElement, _constNode);
+ }
+ }
+ return this;
+ }
}
/**
@@ -3081,9 +3285,9 @@
final UnlinkedParam _unlinkedParam;
/**
- * The context in which type parameters should be interpreted.
+ * The innermost executable element containing this parameter.
*/
- final TypeParameterizedElementForLink _typeParameterContext;
+ final ExecutableElementForLink _innermostExecutable;
/**
* If this parameter has a default value and the enclosing library
@@ -3103,13 +3307,13 @@
final int _parameterIndex;
@override
- final ExecutableElementForLink enclosingElement;
+ final ParameterParentElementForLink enclosingElement;
DartType _inferredType;
DartType _declaredType;
ParameterElementForLink(this.enclosingElement, this._unlinkedParam,
- this._typeParameterContext, this.compilationUnit, this._parameterIndex) {
+ this._innermostExecutable, this.compilationUnit, this._parameterIndex) {
if (_unlinkedParam.defaultValue != null) {
_constNode = new ConstParameterNode(this);
}
@@ -3142,18 +3346,18 @@
if (_unlinkedParam.isFunctionTyped) {
_declaredType = new FunctionTypeImpl(
new FunctionElementForLink_FunctionTypedParam(
- this, enclosingElement, <int>[_parameterIndex]));
+ this, _innermostExecutable, _unlinkedParam.parameters));
} else if (_unlinkedParam.type == null) {
if (!compilationUnit.isInBuildUnit) {
_inferredType = compilationUnit.getLinkedType(
- _unlinkedParam.inferredTypeSlot, _typeParameterContext);
+ _unlinkedParam.inferredTypeSlot, _innermostExecutable);
return _inferredType;
} else {
_declaredType = DynamicTypeImpl.instance;
}
} else {
_declaredType = compilationUnit._resolveTypeRef(
- _unlinkedParam.type, _typeParameterContext);
+ _unlinkedParam.type, _innermostExecutable);
}
}
return _declaredType;
@@ -3171,7 +3375,7 @@
*/
void link(CompilationUnitElementInBuildUnit compilationUnit) {
compilationUnit._storeLinkedType(
- _unlinkedParam.inferredTypeSlot, _inferredType, _typeParameterContext);
+ _unlinkedParam.inferredTypeSlot, _inferredType, _innermostExecutable);
}
@override
@@ -3179,6 +3383,76 @@
}
/**
+ * Element representing the parameter of a synthetic setter for a variable
+ * resynthesized during linking.
+ */
+class ParameterElementForLink_VariableSetter implements ParameterElementImpl {
+ @override
+ final PropertyAccessorElementForLink_Variable enclosingElement;
+
+ ParameterElementForLink_VariableSetter(this.enclosingElement);
+
+ @override
+ bool get isSynthetic => true;
+
+ @override
+ String get name => 'x';
+
+ @override
+ ParameterKind get parameterKind => ParameterKind.REQUIRED;
+
+ @override
+ DartType get type => enclosingElement.computeVariableType();
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Mixin used by elements that can have parameters.
+ */
+abstract class ParameterParentElementForLink implements Element {
+ List<ParameterElementForLink> _parameters;
+
+ /**
+ * Get the appropriate integer list to store in
+ * [EntityRef.implicitFunctionTypeIndices] to refer to this element. For an
+ * element representing a function-typed parameter, this should return a
+ * non-empty list. For an element representing an executable, this should
+ * return the empty list.
+ */
+ List<int> get implicitFunctionTypeIndices;
+
+ /**
+ * Get the innermost enclosing ExecutableElement (which may be [this], or may
+ * be a parent when there are function-typed parameters).
+ */
+ ExecutableElementForLink get innermostExecutable;
+
+ /**
+ * Get all the parameters of this element.
+ */
+ List<ParameterElementForLink> get parameters {
+ if (_parameters == null) {
+ List<UnlinkedParam> unlinkedParameters = this.unlinkedParameters;
+ int numParameters = unlinkedParameters.length;
+ _parameters = new List<ParameterElementForLink>(numParameters);
+ for (int i = 0; i < numParameters; i++) {
+ UnlinkedParam unlinkedParam = unlinkedParameters[i];
+ _parameters[i] = new ParameterElementForLink(this, unlinkedParam,
+ innermostExecutable, innermostExecutable.enclosingUnit, i);
+ }
+ }
+ return _parameters;
+ }
+
+ /**
+ * Get the list of unlinked parameters of this element.
+ */
+ List<UnlinkedParam> get unlinkedParameters;
+}
+
+/**
* Element representing a getter or setter resynthesized from a summary during
* linking.
*/
@@ -3197,10 +3471,11 @@
SyntheticVariableElementForLink variable;
PropertyAccessorElementForLink_Executable(
- ClassElementForLink_Class enclosingElement,
+ ClassElementForLink_Class enclosingClass,
UnlinkedExecutable unlinkedExecutable,
this.variable)
- : super(enclosingElement, unlinkedExecutable);
+ : super(enclosingClass.enclosingElement, enclosingClass,
+ unlinkedExecutable);
@override
PropertyAccessorElementForLink_Executable get correspondingGetter =>
@@ -3220,6 +3495,9 @@
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
}
/**
@@ -3231,19 +3509,20 @@
@override
final bool isSetter;
- final VariableElementForLink _variable;
+ final VariableElementForLink variable;
FunctionTypeImpl _type;
+ List<ParameterElement> _parameters;
- PropertyAccessorElementForLink_Variable(this._variable, this.isSetter);
+ PropertyAccessorElementForLink_Variable(this.variable, this.isSetter);
@override
- Element get enclosingElement => _variable.enclosingElement;
+ Element get enclosingElement => variable.enclosingElement;
@override
bool get isGetter => !isSetter;
@override
- bool get isStatic => _variable.isStatic;
+ bool get isStatic => variable.isStatic;
@override
bool get isSynthetic => true;
@@ -3252,22 +3531,29 @@
ElementKind get kind => isSetter ? ElementKind.SETTER : ElementKind.GETTER;
@override
- String get name => isSetter ? '${_variable.name}=' : _variable.name;
+ LibraryElementForLink get library =>
+ variable.compilationUnit.enclosingElement;
+
+ @override
+ String get name => isSetter ? '${variable.name}=' : variable.name;
+
+ @override
+ List<ParameterElement> get parameters {
+ if (_parameters == null) {
+ _parameters = <ParameterElementForLink_VariableSetter>[];
+ if (isSetter) {
+ _parameters.add(new ParameterElementForLink_VariableSetter(this));
+ }
+ }
+ return _parameters;
+ }
@override
DartType get returnType {
if (isSetter) {
return VoidTypeImpl.instance;
- } else if (_variable.hasImplicitType &&
- !isStatic &&
- !_variable.compilationUnit.isTypeInferenceComplete) {
- // This is an instance field and we are currently inferring types in the
- // library cycle containing it. So we shouldn't use the inferred type
- // (even if we have already computed it), since that would lead to
- // non-deterministic type inference results.
- return DynamicTypeImpl.instance;
} else {
- return _variable.type;
+ return computeVariableType();
}
}
@@ -3280,6 +3566,24 @@
return const [];
}
+ /**
+ * Compute the type of the corresponding variable, which may depend on the
+ * progress of type inference.
+ */
+ DartType computeVariableType() {
+ if (variable.hasImplicitType &&
+ !isStatic &&
+ !variable.compilationUnit.isTypeInferenceComplete) {
+ // This is an instance field and we are currently inferring types in the
+ // library cycle containing it. So we shouldn't use the inferred type
+ // (even if we have already computed it), since that would lead to
+ // non-deterministic type inference results.
+ return DynamicTypeImpl.instance;
+ } else {
+ return variable.type;
+ }
+ }
+
@override
bool isAccessibleIn(LibraryElement library) =>
!Identifier.isPrivateName(name) || identical(this.library, library);
@@ -3289,6 +3593,9 @@
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
}
/**
@@ -3386,6 +3693,9 @@
PropertyAccessorElementForLink_Executable get getter => _getter;
@override
+ bool get isSynthetic => true;
+
+ @override
PropertyAccessorElementForLink_Executable get setter => _setter;
@override
@@ -3396,6 +3706,47 @@
}
/**
+ * Element representing a top-level function.
+ */
+class TopLevelFunctionElementForLink extends ExecutableElementForLink
+ implements FunctionElementImpl, ReferenceableElementForLink {
+ DartType _returnType;
+
+ TopLevelFunctionElementForLink(
+ CompilationUnitElementForLink enclosingUnit, UnlinkedExecutable _buf)
+ : super(enclosingUnit, null, _buf);
+
+ @override
+ ConstructorElementForLink get asConstructor => null;
+
+ @override
+ ConstVariableNode get asConstVariable => null;
+
+ @override
+ DartType get asStaticType => type;
+
+ @override
+ TypeInferenceNode get asTypeInferenceNode => null;
+
+ @override
+ ElementKind get kind => ElementKind.FUNCTION;
+
+ @override
+ DartType buildType(DartType getTypeArgument(int i),
+ List<int> implicitFunctionTypeIndices) =>
+ DynamicTypeImpl.instance;
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) {
+ // TODO(paulberry): handle references to `call`.
+ return UndefinedElementForLink.instance;
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
* Element representing a top level variable resynthesized from a
* summary during linking.
*/
@@ -3419,8 +3770,8 @@
if (hasImplicitType) {
TypeInferenceNode typeInferenceNode = this.asTypeInferenceNode;
if (typeInferenceNode != null) {
- compilationUnit._storeLinkedType(unlinkedVariable.inferredTypeSlot,
- typeInferenceNode.inferredType, null);
+ compilationUnit._storeLinkedType(
+ unlinkedVariable.inferredTypeSlot, inferredType, null);
}
}
}
@@ -3456,27 +3807,10 @@
*/
final VariableElementForLink variableElement;
- /**
- * If a type has been inferred for this node, the inferred type (may be
- * `dynamic`). Otherwise `null`.
- */
- DartType _inferredType;
-
TypeInferenceNode(this.variableElement);
- /**
- * Infer a type for this node if necessary, and return it.
- */
- DartType get inferredType {
- if (_inferredType == null) {
- new TypeInferenceDependencyWalker().walk(this);
- assert(_inferredType != null);
- }
- return _inferredType;
- }
-
@override
- bool get isEvaluated => _inferredType != null;
+ bool get isEvaluated => variableElement._inferredType != null;
/**
* Collect the type inference dependencies in [unlinkedConst] (which should be
@@ -3544,9 +3878,10 @@
void evaluate(bool inCycle) {
if (inCycle) {
- _inferredType = DynamicTypeImpl.instance;
+ variableElement._inferredType = DynamicTypeImpl.instance;
} else {
- _inferredType = new ExprTypeComputer(variableElement).compute();
+ variableElement._inferredType =
+ new ExprTypeComputer(variableElement).compute();
}
}
}
@@ -3555,7 +3890,7 @@
* Element representing a type parameter resynthesized from a summary during
* linking.
*/
-class TypeParameterElementForLink implements TypeParameterElement {
+class TypeParameterElementForLink implements TypeParameterElementImpl {
/**
* The unlinked representation of the type parameter in the summary.
*/
@@ -3567,9 +3902,14 @@
*/
final int nestingLevel;
- TypeParameterTypeImpl _type;
+ @override
+ final TypeParameterizedElementForLink enclosingElement;
- TypeParameterElementForLink(this._unlinkedTypeParam, this.nestingLevel);
+ TypeParameterTypeImpl _type;
+ ElementLocation _location;
+
+ TypeParameterElementForLink(
+ this.enclosingElement, this._unlinkedTypeParam, this.nestingLevel);
@override
DartType get bound {
@@ -3581,9 +3921,16 @@
}
@override
+ String get identifier => name;
+
+ @override
ElementKind get kind => ElementKind.TYPE_PARAMETER;
@override
+ ElementLocation get location =>
+ _location ??= new ElementLocationImpl.con1(this);
+
+ @override
String get name => _unlinkedTypeParam.name;
@override
@@ -3623,7 +3970,7 @@
new List<TypeParameterElementForLink>(numTypeParameters);
for (int i = 0; i < numTypeParameters; i++) {
_typeParameters[i] = new TypeParameterElementForLink(
- _unlinkedTypeParams[i], enclosingNestingLevel + i);
+ this, _unlinkedTypeParams[i], enclosingNestingLevel + i);
}
}
return _typeParameters;
@@ -3847,7 +4194,10 @@
* summary during linking.
*/
class VariableElementForLink
- implements VariableElementImpl, ReferenceableElementForLink {
+ implements
+ VariableElementImpl,
+ PropertyInducingElement,
+ ReferenceableElementForLink {
/**
* The unlinked representation of the variable in the summary.
*/
@@ -3868,7 +4218,8 @@
TypeInferenceNode _typeInferenceNode;
FunctionElementForLink_Initializer _initializer;
- DartType _staticType;
+ DartType _inferredType;
+ DartType _declaredType;
/**
* The compilation unit in which this variable appears.
@@ -3891,32 +4242,55 @@
ConstVariableNode get asConstVariable => _constNode;
@override
- DartType get asStaticType {
- if (_staticType == null) {
- if (_typeInferenceNode != null) {
- assert(_typeInferenceNode.isEvaluated);
- _staticType = _typeInferenceNode.inferredType;
- } else if (hasImplicitType) {
- if (!compilationUnit.isInBuildUnit) {
- _staticType = compilationUnit.getLinkedType(
- unlinkedVariable.inferredTypeSlot, _typeParameterContext);
- } else {
- _staticType = DynamicTypeImpl.instance;
- }
- } else {
- _staticType = compilationUnit._resolveTypeRef(
- unlinkedVariable.type, _typeParameterContext);
- }
- }
- return _staticType;
- }
+ DartType get asStaticType => type;
@override
TypeInferenceNode get asTypeInferenceNode => _typeInferenceNode;
+ /**
+ * If the variable has an explicitly declared return type, return it.
+ * Otherwise return `null`.
+ */
+ DartType get declaredType {
+ if (unlinkedVariable.type == null) {
+ return null;
+ } else {
+ return _declaredType ??= compilationUnit._resolveTypeRef(
+ unlinkedVariable.type, _typeParameterContext);
+ }
+ }
+
@override
bool get hasImplicitType => unlinkedVariable.type == null;
+ /**
+ * Return the inferred type of the variable element. Should only be called if
+ * no type was explicitly declared.
+ */
+ DartType get inferredType {
+ // We should only try to infer a type when none is explicitly declared.
+ assert(unlinkedVariable.type == null);
+ if (_inferredType == null) {
+ if (_typeInferenceNode != null) {
+ assert(Linker._initializerTypeInferenceCycle == null);
+ Linker._initializerTypeInferenceCycle =
+ compilationUnit.library.libraryCycleForLink;
+ try {
+ new TypeInferenceDependencyWalker().walk(_typeInferenceNode);
+ assert(_inferredType != null);
+ } finally {
+ Linker._initializerTypeInferenceCycle = null;
+ }
+ } else if (compilationUnit.isInBuildUnit) {
+ _inferredType = DynamicTypeImpl.instance;
+ } else {
+ _inferredType = compilationUnit.getLinkedType(
+ unlinkedVariable.inferredTypeSlot, _typeParameterContext);
+ }
+ }
+ return _inferredType;
+ }
+
@override
FunctionElementForLink_Initializer get initializer {
if (unlinkedVariable.constExpr == null) {
@@ -3942,6 +4316,15 @@
String get name => unlinkedVariable.name;
@override
+ DartType get propagatedType {
+ // TODO(paulberry): implement propagated types in the linker.
+ return DynamicTypeImpl.instance;
+ }
+
+ @override
+ DartType get type => declaredType ?? inferredType;
+
+ @override
void set type(DartType newType) {
// TODO(paulberry): store inferred type.
}
@@ -3958,9 +4341,29 @@
DynamicTypeImpl.instance;
ReferenceableElementForLink getContainedName(String name) {
- return new NonstaticMemberElementForLink(_constNode);
+ Element element = _getContainedElement(name);
+ return new NonstaticMemberElementForLink(element, _constNode);
}
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ /**
+ * Return the contained element with the given [name], or `null` if the lookup
+ * fails. Currently only static types are supported in the linker, so lookup
+ * is performed only in the strong mode.
+ */
+ Element _getContainedElement(String name) {
+ Linker linker = compilationUnit.library._linker;
+ if (linker.strongMode) {
+ DartType type = asStaticType;
+ if (type is InterfaceType) {
+ Element result = type.lookUpGetter(name, compilationUnit.library);
+ result ??= type.lookUpMethod(name, compilationUnit.library);
+ return result;
+ }
+ }
+ // TODO(scheglov): implement for propagated types
+ return null;
+ }
}
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 63a7f0f..23fecd5 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -1054,18 +1054,25 @@
/**
* Resynthesize an [ImportElement].
*/
- ImportElement buildImport(_UnitResynthesizer definingUnitResynthesizer,
- UnlinkedImport serializedImport, int dependency) {
+ ImportElement buildImport(
+ _UnitResynthesizer definingUnitResynthesizer,
+ UnlinkedImport serializedImport,
+ int dependency,
+ LibraryElement libraryBeingResynthesized) {
bool isSynthetic = serializedImport.isImplicit;
ImportElementImpl importElement =
new ImportElementImpl(isSynthetic ? -1 : serializedImport.offset);
- String absoluteUri = summaryResynthesizer.sourceFactory
- .resolveUri(librarySource, linkedLibrary.dependencies[dependency].uri)
- .uri
- .toString();
- importElement.importedLibrary = new LibraryElementHandle(
- summaryResynthesizer,
- new ElementLocationImpl.con3(<String>[absoluteUri]));
+ if (dependency == 0) {
+ importElement.importedLibrary = libraryBeingResynthesized;
+ } else {
+ String absoluteUri = summaryResynthesizer.sourceFactory
+ .resolveUri(librarySource, linkedLibrary.dependencies[dependency].uri)
+ .uri
+ .toString();
+ importElement.importedLibrary = new LibraryElementHandle(
+ summaryResynthesizer,
+ new ElementLocationImpl.con3(<String>[absoluteUri]));
+ }
if (isSynthetic) {
importElement.synthetic = true;
} else {
@@ -1130,7 +1137,8 @@
imports.add(buildImport(
definingUnitResynthesizer,
unlinkedDefiningUnit.imports[i],
- linkedLibrary.importDependencies[i]));
+ linkedLibrary.importDependencies[i],
+ library));
}
library.imports = imports;
// Create exports.
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index bb2a42e..353de09 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -19,6 +19,7 @@
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/name_filter.dart';
import 'package:analyzer/src/summary/summarize_const_expr.dart';
+import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:path/path.dart' as path;
@@ -136,7 +137,16 @@
final List<LinkedLibraryBuilder> _linkedLibraries = <LinkedLibraryBuilder>[];
final List<String> _unlinkedUnitUris = <String>[];
final List<UnlinkedUnitBuilder> _unlinkedUnits = <UnlinkedUnitBuilder>[];
- final List<String> _unlinkedUnitHashes = <String>[];
+ final List<String> _unlinkedUnitHashes;
+ final bool _excludeHashes;
+
+ /**
+ * Create a [PackageBundleAssembler]. If [excludeHashes] is `true`, hash
+ * computation will be skipped.
+ */
+ PackageBundleAssembler({bool excludeHashes: false})
+ : _excludeHashes = excludeHashes,
+ _unlinkedUnitHashes = excludeHashes ? null : <String>[];
/**
* Add a fallback library to the package bundle, corresponding to the library
@@ -167,13 +177,15 @@
}
void addUnlinkedUnit(Source source, UnlinkedUnitBuilder unit) {
- addUnlinkedUnitWithHash(source.uri.toString(), unit, _hash(source.contents.data));
+ addUnlinkedUnitWithHash(source.uri.toString(), unit,
+ _excludeHashes ? null : _hash(source.contents.data));
}
- void addUnlinkedUnitWithHash(String uri, UnlinkedUnitBuilder unit, String hash) {
+ void addUnlinkedUnitWithHash(
+ String uri, UnlinkedUnitBuilder unit, String hash) {
_unlinkedUnitUris.add(uri);
_unlinkedUnits.add(unit);
- _unlinkedUnitHashes.add(hash);
+ _unlinkedUnitHashes?.add(hash);
}
/**
@@ -204,7 +216,7 @@
_unlinkedUnitUris.addAll(libraryResult.unitUris);
_unlinkedUnits.addAll(libraryResult.unlinkedUnits);
for (Source source in libraryResult.unitSources) {
- _unlinkedUnitHashes.add(_hash(source.contents.data));
+ _unlinkedUnitHashes?.add(_hash(source.contents.data));
}
}
@@ -212,9 +224,7 @@
* Compute a hash of the given file contents.
*/
String _hash(String contents) {
- MD5 md5 = new MD5();
- md5.add(UTF8.encode(contents));
- return CryptoUtils.bytesToHex(md5.close());
+ return hex.encode(md5.convert(UTF8.encode(contents)).bytes);
}
}
@@ -328,7 +338,7 @@
new UnlinkedReferenceBuilder()
];
linkedReferences = <LinkedReferenceBuilder>[
- new LinkedReferenceBuilder(kind: ReferenceKind.classOrEnum)
+ new LinkedReferenceBuilder(kind: ReferenceKind.unresolved)
];
List<UnlinkedPublicNameBuilder> names = <UnlinkedPublicNameBuilder>[];
for (PropertyAccessorElement accessor in compilationUnit.accessors) {
@@ -1328,6 +1338,15 @@
constructor = serializeConstructorName(
new TypeName(annotation.name, null)..type = nameElement.type,
annotation.constructorName);
+ } else if (nameElement == null) {
+ // Unresolved annotation.
+ if (name is PrefixedIdentifier && annotation.constructorName == null) {
+ constructor = serializeConstructorName(
+ new TypeName(name.prefix, null), name.identifier);
+ } else {
+ constructor = serializeConstructorName(
+ new TypeName(annotation.name, null), annotation.constructorName);
+ }
} else {
throw new StateError('Unexpected annotation nameElement type:'
' ${nameElement.runtimeType}');
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 3faab08..f38ede3 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -14,7 +14,7 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart'
- show DartUriResolver, Source, SourceFactory, SourceKind;
+ show Source, SourceFactory, SourceKind;
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/task/dart.dart';
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 3f80560..283bca3 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -16,6 +16,7 @@
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/constant.dart';
@@ -616,6 +617,17 @@
new ResultDescriptor<ReferencedNames>('REFERENCED_NAMES', null);
/**
+ * The sources of the Dart files that a library references.
+ *
+ * The list is the union of [IMPORTED_LIBRARIES], [EXPORTED_LIBRARIES] and
+ * [UNITS] of the defining unit and [INCLUDED_PARTS]. Never empty or `null`.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ListResultDescriptor<Source> REFERENCED_SOURCES =
+ new ListResultDescriptor<Source>('REFERENCED_SOURCES', Source.EMPTY_LIST);
+
+/**
* The errors produced while resolving type names.
*
* The list will be empty if there were no errors, but will not be `null`.
@@ -995,6 +1007,12 @@
static const String UNIT_INPUT_NAME = 'UNIT_INPUT_NAME';
/**
+ * The input with a map from referenced sources to their modification times.
+ */
+ static const String SOURCES_MODIFICATION_TIME_INPUT_NAME =
+ 'SOURCES_MODIFICATION_TIME_INPUT_NAME';
+
+ /**
* The input with a list of [LIBRARY_ELEMENT3]s of imported libraries.
*/
static const String IMPORTS_LIBRARY_ELEMENT_INPUT_NAME =
@@ -1041,6 +1059,8 @@
//
LibraryElementImpl libraryElement = getRequiredInput(LIBRARY_INPUT);
CompilationUnit libraryUnit = getRequiredInput(UNIT_INPUT_NAME);
+ Map<Source, int> sourceModificationTimeMap =
+ getRequiredInput(SOURCES_MODIFICATION_TIME_INPUT_NAME);
Map<Source, LibraryElement> importLibraryMap =
getRequiredInput(IMPORTS_LIBRARY_ELEMENT_INPUT_NAME);
Map<Source, LibraryElement> exportLibraryMap =
@@ -1072,6 +1092,7 @@
DirectiveElementBuilder builder = new DirectiveElementBuilder(
context,
libraryElement,
+ sourceModificationTimeMap,
importLibraryMap,
importSourceKindMap,
exportLibraryMap,
@@ -1103,6 +1124,8 @@
LIBRARY_INPUT: LIBRARY_ELEMENT1.of(source),
UNIT_INPUT_NAME:
RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, source)),
+ SOURCES_MODIFICATION_TIME_INPUT_NAME:
+ REFERENCED_SOURCES.of(source).toMapOf(MODIFICATION_TIME),
IMPORTS_LIBRARY_ELEMENT_INPUT_NAME:
IMPORTED_LIBRARIES.of(source).toMapOf(LIBRARY_ELEMENT1),
EXPORTS_LIBRARY_ELEMENT_INPUT_NAME:
@@ -1359,16 +1382,15 @@
libraryNameNode = directive.name;
directivesToResolve.add(directive);
} else if (directive is PartDirective) {
- PartDirective partDirective = directive;
- StringLiteral partUri = partDirective.uri;
- Source partSource = partDirective.source;
+ StringLiteral partUri = directive.uri;
+ Source partSource = directive.source;
hasPartDirective = true;
CompilationUnit partUnit = partUnitMap[partSource];
if (partUnit != null) {
CompilationUnitElementImpl partElement = partUnit.element;
partElement.uriOffset = partUri.offset;
partElement.uriEnd = partUri.end;
- partElement.uri = partDirective.uriContent;
+ partElement.uri = directive.uriContent;
//
// Validate that the part contains a part-of directive with the same
// name as the library.
@@ -2342,6 +2364,8 @@
* of errors.
*/
class DartErrorsTask extends SourceBasedAnalysisTask {
+ static final RegExp spacesRegExp = new RegExp(r'\s+');
+
/**
* The task descriptor describing this kind of task.
*/
@@ -2398,13 +2422,19 @@
outputs[DART_ERRORS] = errors;
}
+ Token _advanceToLine(Token token, LineInfo lineInfo, int line) {
+ int offset = lineInfo.getOffsetOfLine(line - 1); // 0-based
+ while (token.offset < offset) {
+ token = token.next;
+ }
+ return token;
+ }
+
List<AnalysisError> _filterIgnores(List<AnalysisError> errors) {
if (errors.isEmpty) {
return errors;
}
- List<AnalysisError> filtered = <AnalysisError>[];
-
// Sort errors.
errors.sort((AnalysisError e1, AnalysisError e2) => e1.offset - e2.offset);
@@ -2412,58 +2442,50 @@
Token token = cu.beginToken;
LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT);
- int errorIndex = 0;
+ bool isIgnored(AnalysisError error) {
+ int errorLine = lineInfo.getLocation(error.offset).lineNumber;
+ token = _advanceToLine(token, lineInfo, errorLine);
- // Step through tokens looking for comments.
- while (errorIndex < errors.length && token.type != TokenType.EOF) {
- // Find leading comment.
+ //Check for leading comment.
Token comments = token.precedingComments;
while (comments?.next != null) {
comments = comments.next;
}
+ if (_isIgnoredBy(error, comments)) {
+ return true;
+ }
- // Normalize content.
- String comment =
- comments?.lexeme?.toLowerCase()?.replaceAll(new RegExp(r'\s+'), '');
-
- // Check for ignores.
- if (comment != null && comment.startsWith(_normalizedIgnorePrefix)) {
- int affectedLine = lineInfo.getLocation(token.offset).lineNumber;
-
- // Process all affected errors.
- while (errorIndex < errors.length) {
- AnalysisError currentError = errors[errorIndex++];
- int errorLine = lineInfo.getLocation(currentError.offset).lineNumber;
- if (errorLine < affectedLine) {
- filtered.add(currentError);
- } else if (errorLine == affectedLine) {
- // Check for an ignore.
- if (!_isIgnoredBy(currentError, comment)) {
- filtered.add(currentError);
- }
- } else {
- // Back up index and break.
- --errorIndex;
- break;
+ //Check for trailing comment.
+ int lineNumber = errorLine + 1;
+ if (lineNumber <= lineInfo.lineCount) {
+ Token nextLine = _advanceToLine(token, lineInfo, lineNumber);
+ comments = nextLine.precedingComments;
+ if (comments != null && nextLine.previous.type != TokenType.EOF) {
+ int commentLine = lineInfo.getLocation(comments.offset).lineNumber;
+ if (commentLine == errorLine) {
+ return _isIgnoredBy(error, comments);
}
}
}
- token = token.next;
+ return false;
}
- // Add remaining errors.
- if (errorIndex < errors.length) {
- filtered.addAll(errors.sublist(errorIndex));
- }
-
- return filtered;
+ return errors.where((AnalysisError e) => !isIgnored(e)).toList();
}
- bool _isIgnoredBy(AnalysisError error, String comment) => comment
- .substring(_normalizedIgnorePrefix.length)
- .split(',')
- .contains(error.errorCode.name.toLowerCase());
+ bool _isIgnoredBy(AnalysisError error, Token comment) {
+ //Normalize first.
+ String contents =
+ comment?.lexeme?.toLowerCase()?.replaceAll(spacesRegExp, '');
+ if (contents == null || !contents.startsWith(_normalizedIgnorePrefix)) {
+ return false;
+ }
+ return contents
+ .substring(_normalizedIgnorePrefix.length)
+ .split(',')
+ .contains(error.errorCode.name.toLowerCase());
+ }
/**
* Return a map from the names of the inputs of this kind of task to the task
@@ -3474,7 +3496,8 @@
PARSE_ERRORS,
PARSED_UNIT,
SOURCE_KIND,
- UNITS
+ UNITS,
+ REFERENCED_SOURCES
]);
/**
@@ -3500,7 +3523,6 @@
parser.parseAsync = options.enableAsync;
parser.parseFunctionBodies = options.analyzeFunctionBodiesPredicate(source);
parser.parseGenericMethods = options.enableGenericMethods;
- parser.parseConditionalDirectives = options.enableConditionalDirectives;
parser.parseGenericMethodComments = options.strongMode;
CompilationUnit unit = parser.parseCompilationUnit(tokenStream);
unit.lineInfo = lineInfo;
@@ -3569,6 +3591,11 @@
List<Source> includedSources = includedSourceSet.toList();
List<AnalysisError> parseErrors = getUniqueErrors(errorListener.errors);
List<Source> unitSources = <Source>[source]..addAll(includedSourceSet);
+ List<Source> referencedSources = (new Set<Source>()
+ ..addAll(importedSources)
+ ..addAll(exportedSources)
+ ..addAll(unitSources))
+ .toList();
List<LibrarySpecificUnit> librarySpecificUnits =
unitSources.map((s) => new LibrarySpecificUnit(source, s)).toList();
outputs[EXPLICITLY_IMPORTED_LIBRARIES] = explicitlyImportedSources;
@@ -3580,6 +3607,7 @@
outputs[PARSED_UNIT] = unit;
outputs[SOURCE_KIND] = sourceKind;
outputs[UNITS] = unitSources;
+ outputs[REFERENCED_SOURCES] = referencedSources;
}
/**
@@ -4489,20 +4517,12 @@
//
// Resolve references.
//
- // TODO(leafp): This code only needs to re-resolve the right hand sides of
- // instance fields. We could do incremental resolution on each field
- // only using the incremental resolver. However, this caused a massive
- // performance degredation on the large_class_declaration_test.dart test.
- // I would hypothesize that incremental resolution of field is linear in
- // the size of the enclosing class, and hence incrementally resolving each
- // field was quadratic. We may wish to revisit this if we can resolve
- // this performance issue.
- PartialResolverVisitor visitor = new PartialResolverVisitor(
+ InstanceFieldResolverVisitor visitor = new InstanceFieldResolverVisitor(
libraryElement,
unitElement.source,
typeProvider,
AnalysisErrorListener.NULL_LISTENER);
- unit.accept(visitor);
+ visitor.resolveCompilationUnit(unit);
}
//
// Record outputs.
@@ -5062,6 +5082,11 @@
static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
/**
+ * The name of the input whose value is the modification time of the file.
+ */
+ static const String MODIFICATION_TIME_INPUT = 'MODIFICATION_TIME_INPUT';
+
+ /**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -5084,9 +5109,10 @@
@override
void internalPerform() {
Source source = getRequiredSource();
-
RecordingErrorListener errorListener = new RecordingErrorListener();
- if (context.getModificationStamp(target.source) < 0) {
+
+ int modificationTime = getRequiredInput(MODIFICATION_TIME_INPUT);
+ if (modificationTime < 0) {
String message = 'Content could not be read';
if (context is InternalAnalysisContext) {
CacheEntry entry =
@@ -5143,16 +5169,23 @@
/**
* Return a map from the names of the inputs of this kind of task to the task
* input descriptors describing those inputs for a task with the given
- * [source].
+ * [target].
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
if (target is Source) {
- return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(target)};
+ return <String, TaskInput>{
+ CONTENT_INPUT_NAME: CONTENT.of(target),
+ MODIFICATION_TIME_INPUT: MODIFICATION_TIME.of(target)
+ };
} else if (target is DartScript) {
// This task does not use the following input; it is included only to add
// a dependency between this value and the containing source so that when
// the containing source is modified these results will be invalidated.
- return <String, TaskInput>{'-': DART_SCRIPTS.of(target.source)};
+ Source source = target.source;
+ return <String, TaskInput>{
+ '-': DART_SCRIPTS.of(source),
+ MODIFICATION_TIME_INPUT: MODIFICATION_TIME.of(source)
+ };
}
throw new AnalysisException(
'Cannot build inputs for a ${target.runtimeType}');
@@ -5269,6 +5302,13 @@
static const String UNIT_INPUT = 'UNIT_INPUT';
/**
+ * The name of the input of a mapping from [REFERENCED_SOURCES] to their
+ * [MODIFICATION_TIME]s.
+ */
+ static const String REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT =
+ 'REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT';
+
+ /**
* The name of the [TYPE_PROVIDER] input.
*/
static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
@@ -5284,6 +5324,12 @@
*/
ErrorReporter errorReporter;
+ /**
+ * The mapping from the current library referenced sources to their
+ * modification times.
+ */
+ Map<Source, int> sourceTimeMap;
+
VerifyUnitTask(InternalAnalysisContext context, AnalysisTarget target)
: super(context, target);
@@ -5300,6 +5346,8 @@
//
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ sourceTimeMap =
+ getRequiredInput(REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT);
CompilationUnitElement unitElement = unit.element;
LibraryElement libraryElement = unitElement.library;
if (libraryElement == null) {
@@ -5354,7 +5402,8 @@
void validateReferencedSource(UriBasedDirective directive) {
Source source = directive.source;
if (source != null) {
- if (context.exists(source)) {
+ int modificationTime = sourceTimeMap[source] ?? -1;
+ if (modificationTime >= 0) {
return;
}
} else {
@@ -5378,6 +5427,8 @@
return <String, TaskInput>{
'thisLibraryClosureIsReady': READY_RESOLVED_UNIT.of(unit.library),
UNIT_INPUT: RESOLVED_UNIT.of(unit),
+ REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT:
+ REFERENCED_SOURCES.of(unit.library).toMapOf(MODIFICATION_TIME),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
};
}
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 4a81c18..0eb6613 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -8,13 +8,7 @@
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/generated/engine.dart'
- show
- AnalysisEngine,
- AnalysisErrorInfo,
- AnalysisErrorInfoImpl,
- AnalysisOptions,
- CacheState,
- InternalAnalysisContext;
+ show AnalysisEngine, AnalysisErrorInfo, CacheState, InternalAnalysisContext;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index c41c41a..b0cabae 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -608,7 +608,7 @@
/**
* The inputs to the task that have been computed.
*/
- Map<String, dynamic> inputs;
+ Map<String, dynamic> inputs = const <String, dynamic>{};
/**
* The exception that was found while trying to populate the inputs. If this
@@ -643,7 +643,6 @@
if (!builder.moveNext()) {
builder = null;
}
- inputs = new HashMap<String, dynamic>();
}
@override
diff --git a/pkg/analyzer/lib/src/task/html.dart b/pkg/analyzer/lib/src/task/html.dart
index 2575677..93e00ed 100644
--- a/pkg/analyzer/lib/src/task/html.dart
+++ b/pkg/analyzer/lib/src/task/html.dart
@@ -269,6 +269,11 @@
static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
/**
+ * The name of the input whose value is the modification time of the file.
+ */
+ static const String MODIFICATION_TIME_INPUT = 'MODIFICATION_TIME_INPUT';
+
+ /**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -292,7 +297,8 @@
void internalPerform() {
String content = getRequiredInput(CONTENT_INPUT_NAME);
- if (context.getModificationStamp(target.source) < 0) {
+ int modificationTime = getRequiredInput(MODIFICATION_TIME_INPUT);
+ if (modificationTime < 0) {
String message = 'Content could not be read';
if (context is InternalAnalysisContext) {
CacheEntry entry =
@@ -343,7 +349,10 @@
* [source].
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget source) {
- return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)};
+ return <String, TaskInput>{
+ CONTENT_INPUT_NAME: CONTENT.of(source),
+ MODIFICATION_TIME_INPUT: MODIFICATION_TIME.of(source)
+ };
}
/**
diff --git a/pkg/analyzer/lib/src/task/html_work_manager.dart b/pkg/analyzer/lib/src/task/html_work_manager.dart
index b0e52bb..07dfb29 100644
--- a/pkg/analyzer/lib/src/task/html_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/html_work_manager.dart
@@ -8,13 +8,7 @@
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/generated/engine.dart'
- show
- AnalysisEngine,
- AnalysisErrorInfo,
- AnalysisErrorInfoImpl,
- AnalysisOptions,
- CacheState,
- InternalAnalysisContext;
+ show AnalysisEngine, AnalysisErrorInfo, CacheState, InternalAnalysisContext;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
index b3b3512..d7156e4 100644
--- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
@@ -303,7 +303,7 @@
static Token getBeginTokenNotComment(AstNode node) {
Token oldBeginToken = node.beginToken;
if (oldBeginToken is CommentToken) {
- oldBeginToken = (oldBeginToken as CommentToken).parent;
+ return oldBeginToken.parent;
}
return oldBeginToken;
}
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index d3cc82f..47acf37 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -48,6 +48,8 @@
static const String enableGenericMethods = 'enableGenericMethods';
static const String enableStrictCallChecks = 'enableStrictCallChecks';
static const String enableSuperMixins = 'enableSuperMixins';
+
+ /// This option is deprecated.
static const String enableConditionalDirectives =
"enableConditionalDirectives";
static const String errors = 'errors';
@@ -496,14 +498,6 @@
context.analysisOptions = options;
}
}
- if (feature == AnalyzerOptions.enableConditionalDirectives) {
- if (isTrue(value)) {
- AnalysisOptionsImpl options =
- new AnalysisOptionsImpl.from(context.analysisOptions);
- options.enableConditionalDirectives = true;
- context.analysisOptions = options;
- }
- }
}
void setLanguageOptions(AnalysisContext context, Object configs) {
diff --git a/pkg/analyzer/lib/src/task/options_work_manager.dart b/pkg/analyzer/lib/src/task/options_work_manager.dart
index bade2fc..2074eb0 100644
--- a/pkg/analyzer/lib/src/task/options_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/options_work_manager.dart
@@ -8,13 +8,7 @@
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/generated/engine.dart'
- show
- AnalysisEngine,
- AnalysisErrorInfo,
- AnalysisErrorInfoImpl,
- AnalysisOptions,
- CacheState,
- InternalAnalysisContext;
+ show AnalysisEngine, AnalysisErrorInfo, CacheState, InternalAnalysisContext;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/options.dart';
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index eaa8599..08d414b 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -8,11 +8,10 @@
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
+import 'package:analyzer/dart/ast/token.dart' show TokenType;
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:analyzer/src/generated/type_system.dart';
@@ -118,10 +117,8 @@
void checkArgument(Expression arg, DartType expectedType) {
// Preserve named argument structure, so their immediate parent is the
// method invocation.
- if (arg is NamedExpression) {
- arg = (arg as NamedExpression).expression;
- }
- checkAssignment(arg, expectedType);
+ Expression baseExpression = arg is NamedExpression ? arg.expression : arg;
+ checkAssignment(baseExpression, expectedType);
}
void checkArgumentList(ArgumentList node, FunctionType type) {
@@ -428,16 +425,22 @@
@override
void visitListLiteral(ListLiteral node) {
- var type = DynamicTypeImpl.instance;
+ DartType type = DynamicTypeImpl.instance;
if (node.typeArguments != null) {
- var targs = node.typeArguments.arguments;
- if (targs.length > 0) type = targs[0].type;
- } else if (node.staticType is InterfaceType) {
- InterfaceType listT = node.staticType;
- var targs = listT.typeArguments;
- if (targs != null && targs.length > 0) type = targs[0];
+ NodeList<TypeName> targs = node.typeArguments.arguments;
+ if (targs.length > 0) {
+ type = targs[0].type;
+ }
+ } else {
+ DartType staticType = node.staticType;
+ if (staticType is InterfaceType) {
+ List<DartType> targs = staticType.typeArguments;
+ if (targs != null && targs.length > 0) {
+ type = targs[0];
+ }
+ }
}
- var elements = node.elements;
+ NodeList<Expression> elements = node.elements;
for (int i = 0; i < elements.length; i++) {
checkArgument(elements[i], type);
}
@@ -446,23 +449,33 @@
@override
void visitMapLiteral(MapLiteral node) {
- var ktype = DynamicTypeImpl.instance;
- var vtype = DynamicTypeImpl.instance;
+ DartType ktype = DynamicTypeImpl.instance;
+ DartType vtype = DynamicTypeImpl.instance;
if (node.typeArguments != null) {
- var targs = node.typeArguments.arguments;
- if (targs.length > 0) ktype = targs[0].type;
- if (targs.length > 1) vtype = targs[1].type;
- } else if (node.staticType is InterfaceType) {
- InterfaceType mapT = node.staticType;
- var targs = mapT.typeArguments;
- if (targs != null) {
- if (targs.length > 0) ktype = targs[0];
- if (targs.length > 1) vtype = targs[1];
+ NodeList<TypeName> targs = node.typeArguments.arguments;
+ if (targs.length > 0) {
+ ktype = targs[0].type;
+ }
+ if (targs.length > 1) {
+ vtype = targs[1].type;
+ }
+ } else {
+ DartType staticType = node.staticType;
+ if (staticType is InterfaceType) {
+ List<DartType> targs = staticType.typeArguments;
+ if (targs != null) {
+ if (targs.length > 0) {
+ ktype = targs[0];
+ }
+ if (targs.length > 1) {
+ vtype = targs[1];
+ }
+ }
}
}
- var entries = node.entries;
+ NodeList<MapLiteralEntry> entries = node.entries;
for (int i = 0; i < entries.length; i++) {
- var entry = entries[i];
+ MapLiteralEntry entry = entries[i];
checkArgument(entry.key, ktype);
checkArgument(entry.value, vtype);
}
@@ -800,7 +813,7 @@
// Remove fuzzy arrow if possible.
if (t is FunctionType && StaticInfo.isKnownFunction(expr)) {
- t = _removeFuzz(t);
+ t = rules.functionTypeToConcreteType(typeProvider, t);
}
return t;
@@ -821,7 +834,9 @@
if (t is InterfaceType) {
return rules.getCallMethodType(t);
}
- if (t is FunctionType) return t;
+ if (t is FunctionType) {
+ return t;
+ }
return null;
}
@@ -908,55 +923,6 @@
}
}
- /// Remove "fuzzy arrow" in this function type.
- ///
- /// Normally we treat dynamically typed parameters as bottom for function
- /// types. This allows type tests such as `if (f is SingleArgFunction)`.
- /// It also requires a dynamic check on the parameter type to call these
- /// functions.
- ///
- /// When we convert to a strict arrow, dynamically typed parameters become
- /// top. This is safe to do for known functions, like top-level or local
- /// functions and static methods. Those functions must already be essentially
- /// treating dynamic as top.
- ///
- /// Only the outer-most arrow can be strict. Any others must be fuzzy, because
- /// we don't know what function value will be passed there.
- // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function
- // type? That would allow us to implement this in the subtype relation.
- // TODO(jmesserly): we'll need to factor this differently if we want to
- // move CodeChecker's functionality into existing analyzer. Likely we can
- // let the Expression have a strict arrow, then in places were we do
- // inference, convert back to a fuzzy arrow.
- FunctionType _removeFuzz(FunctionType t) {
- bool foundFuzz = false;
- List<ParameterElement> parameters = <ParameterElement>[];
- for (ParameterElement p in t.parameters) {
- ParameterElement newP = _removeParameterFuzz(p);
- parameters.add(newP);
- if (p != newP) foundFuzz = true;
- }
- if (!foundFuzz) {
- return t;
- }
-
- FunctionElementImpl function = new FunctionElementImpl("", -1);
- function.synthetic = true;
- function.returnType = t.returnType;
- function.shareTypeParameters(t.typeFormals);
- function.shareParameters(parameters);
- return function.type = new FunctionTypeImpl(function);
- }
-
- /// Removes fuzzy arrow, see [_removeFuzz].
- ParameterElement _removeParameterFuzz(ParameterElement p) {
- if (p.type.isDynamic) {
- return new ParameterElementImpl.synthetic(
- p.name, typeProvider.objectType, p.parameterKind);
- }
- return p;
- }
-
DartType _specializedBinaryReturnType(
TokenType op, DartType t1, DartType t2, DartType normalReturnType) {
// This special cases binary return types as per 16.26 and 16.27 of the
@@ -1061,11 +1027,15 @@
InterfaceType baseType, Set<String> seen, bool isSubclass) {
for (var member in node.members) {
if (member is FieldDeclaration) {
- if (member.isStatic) continue;
+ if (member.isStatic) {
+ continue;
+ }
for (var variable in member.fields.variables) {
var element = variable.element as PropertyInducingElement;
var name = element.name;
- if (seen.contains(name)) continue;
+ if (seen.contains(name)) {
+ continue;
+ }
var getter = element.getter;
var setter = element.setter;
bool found = _checkSingleOverride(
@@ -1076,12 +1046,18 @@
setter, baseType, variable.name, member, isSubclass)) {
found = true;
}
- if (found) seen.add(name);
+ if (found) {
+ seen.add(name);
+ }
}
} else if (member is MethodDeclaration) {
- if (member.isStatic) continue;
+ if (member.isStatic) {
+ continue;
+ }
var method = member.element;
- if (seen.contains(method.name)) continue;
+ if (seen.contains(method.name)) {
+ continue;
+ }
if (_checkSingleOverride(
method, baseType, member.name, member, isSubclass)) {
seen.add(method.name);
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 233e5c4..70d31aa 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/generated/resolver.dart'
show TypeProvider, InheritanceManager;
import 'package:analyzer/src/generated/type_system.dart';
@@ -468,10 +469,13 @@
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
if (!node.inDeclarationContext()) {
- Element element = node.staticElement;
- if (element is PropertyAccessorElement && element.isSynthetic) {
- element = (element as PropertyAccessorElement).variable;
+ Element nonAccessor(Element element) {
+ if (element is PropertyAccessorElement && element.isSynthetic) {
+ return element.variable;
+ }
+ return element;
}
+ Element element = nonAccessor(node.staticElement);
if (element is VariableElement && (filter == null || filter(element))) {
results.add(element);
}
diff --git a/pkg/analyzer/lib/src/task/yaml.dart b/pkg/analyzer/lib/src/task/yaml.dart
index e83fa8c..2d94165 100644
--- a/pkg/analyzer/lib/src/task/yaml.dart
+++ b/pkg/analyzer/lib/src/task/yaml.dart
@@ -6,7 +6,7 @@
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index be60b78..557a763 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -7,7 +7,7 @@
import 'dart:collection';
import 'dart:developer';
-import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart' show AnalysisError;
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -185,11 +185,11 @@
* Return the value of the input with the given [name]. Throw an exception if
* the input value is not defined.
*/
- Object getRequiredInput(String name) {
+ Object/*=E*/ getRequiredInput/*<E>*/(String name) {
if (inputs == null || !inputs.containsKey(name)) {
throw new AnalysisException("Could not $description: missing $name");
}
- return inputs[name];
+ return inputs[name] as Object/*=E*/;
}
/**
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 4b0b2ad..6c8b8cc 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.3-alpha.7
+version: 0.27.3
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -7,7 +7,7 @@
sdk: '>=1.12.0 <2.0.0'
dependencies:
args: '>=0.12.1 <0.14.0'
- crypto: ^0.9.0
+ crypto: '>=0.9.2 <2.0.0'
glob: ^1.0.3
html: ^0.12.0
package_config: ^0.1.1
diff --git a/pkg/analyzer/test/generated/error_suppression_test.dart b/pkg/analyzer/test/generated/error_suppression_test.dart
index c77bb3d..275e94c 100644
--- a/pkg/analyzer/test/generated/error_suppression_test.dart
+++ b/pkg/analyzer/test/generated/error_suppression_test.dart
@@ -42,6 +42,25 @@
[CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
}
+ void test_ignore_first_trailing() {
+ Source source = addSource('''
+int x = ''; // ignore: invalid_assignment
+// ... but no ignore here ...
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
+ }
+
+ void test_ignore_only_trailing() {
+ Source source = addSource('''
+int x = ''; // ignore: invalid_assignment
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ }
+
void test_ignore_second() {
Source source = addSource('''
//INVALID_ASSIGNMENT
@@ -53,6 +72,16 @@
assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
}
+ void test_ignore_second_trailing() {
+ Source source = addSource('''
+//INVALID_ASSIGNMENT
+int x = '';
+const y = x; // ignore: const_initialized_with_non_constant_value
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ }
+
void test_invalid_error_code() {
Source source = addSource('''
// ignore: right_format_wrong_code
@@ -108,6 +137,15 @@
assertErrors(source, []);
}
+ void test_multiple_ignores_traling() {
+ Source source = addSource('''
+int x = 3;
+const String y = x; // ignore: invalid_assignment, const_initialized_with_non_constant_value
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ }
+
void test_multiple_ignores_whitespace_variant_1() {
Source source = addSource('''
int x = 3;
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 168c471..79cb436 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -1605,7 +1605,7 @@
}
''');
computeLibrarySourceErrors(source);
- assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM]);
+ assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS]);
verify([source]);
}
@@ -1671,7 +1671,7 @@
}
''');
computeLibrarySourceErrors(source);
- assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM]);
+ assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS]);
verify([source]);
}
@@ -1686,7 +1686,7 @@
}
''');
computeLibrarySourceErrors(source);
- assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM]);
+ assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS]);
verify([source]);
}
@@ -1710,6 +1710,50 @@
verify([source]);
}
+ void test_undefinedIdentifier_importHide() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart' hide a;''');
+ addNamedSource("/lib1.dart", "library lib1;");
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source,
+ [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_HIDDEN_NAME]);
+ verify([source]);
+ }
+
+ void test_undefinedIdentifier_importShow() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart' show a;''');
+ addNamedSource("/lib1.dart", "library lib1;");
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source,
+ [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_SHOWN_NAME]);
+ verify([source]);
+ }
+
+ void test_undefinedIdentifier_exportHide() {
+ Source source = addSource(r'''
+library L;
+export 'lib1.dart' hide a;''');
+ addNamedSource("/lib1.dart", "library lib1;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_HIDDEN_NAME]);
+ verify([source]);
+ }
+
+ void test_undefinedIdentifier_exportShow() {
+ Source source = addSource(r'''
+library L;
+export 'lib1.dart' show a;''');
+ addNamedSource("/lib1.dart", "library lib1;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_SHOWN_NAME]);
+ verify([source]);
+ }
+
void test_undefinedGetter() {
Source source = addSource(r'''
class A {}
@@ -2909,7 +2953,8 @@
import 'lib1.dart' show A, B;
A a;''');
Source source2 = addNamedSource(
- "/lib1.dart", r'''
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}''');
@@ -2947,7 +2992,8 @@
import 'lib1.dart' as p show A, B;
p.A a;''');
Source source2 = addNamedSource(
- "/lib1.dart", r'''
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}''');
@@ -2965,16 +3011,16 @@
A a;
C c;''');
Source source2 = addNamedSource(
- "/lib1.dart", r'''
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}
class C {}
class D {}''');
computeLibrarySourceErrors(source);
- assertErrors(source, [
- HintCode.UNUSED_SHOWN_NAME,
- HintCode.UNUSED_SHOWN_NAME]);
+ assertErrors(
+ source, [HintCode.UNUSED_SHOWN_NAME, HintCode.UNUSED_SHOWN_NAME]);
assertNoErrors(source2);
verify([source, source2]);
}
diff --git a/pkg/analyzer/test/generated/inheritance_manager_test.dart b/pkg/analyzer/test/generated/inheritance_manager_test.dart
index e41df2f..e4f8395 100644
--- a/pkg/analyzer/test/generated/inheritance_manager_test.dart
+++ b/pkg/analyzer/test/generated/inheritance_manager_test.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine_io.dart';
@@ -69,13 +70,13 @@
ElementFactory.getterElement(getterName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getterG];
ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(getterName), same(getterG));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[getterName], same(getterG));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -90,13 +91,13 @@
classA.accessors = <PropertyAccessorElement>[getterG];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.interfaces = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject);
- expect(mapB.get(getterName), isNull);
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject);
+ expect(mapB[getterName], isNull);
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -111,13 +112,13 @@
classA.accessors = <PropertyAccessorElement>[getterG];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.mixins = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(getterName), same(getterG));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[getterName], same(getterG));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -125,9 +126,9 @@
void test_getMapOfMembersInheritedFromClasses_implicitExtends() {
// class A {}
ClassElementImpl classA = ElementFactory.classElement2("A");
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
_assertNoErrors(classA);
}
@@ -141,13 +142,13 @@
classA.methods = <MethodElement>[methodM];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.supertype = classA.type;
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(methodName), same(methodM));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[methodName], same(methodM));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -162,13 +163,13 @@
classA.methods = <MethodElement>[methodM];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.interfaces = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject);
- expect(mapB.get(methodName), isNull);
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject);
+ expect(mapB[methodName], isNull);
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -183,13 +184,13 @@
classA.methods = <MethodElement>[methodM];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.mixins = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(methodName), same(methodM));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromClasses(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[methodName], same(methodM));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -209,9 +210,9 @@
classA2.methods = <MethodElement>[methodA2M];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.mixins = <InterfaceType>[classA1.type, classA2.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
- expect(mapB.get(methodName), same(methodA2M));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromClasses(classB);
+ expect(mapB[methodName], same(methodA2M));
_assertNoErrors(classA1);
_assertNoErrors(classA2);
_assertNoErrors(classB);
@@ -226,13 +227,13 @@
ElementFactory.getterElement(getterName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getterG];
ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(getterName), same(getterG));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[getterName], same(getterG));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -247,13 +248,13 @@
classA.accessors = <PropertyAccessorElement>[getterG];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.interfaces = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(getterName), same(getterG));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[getterName], same(getterG));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -268,13 +269,13 @@
classA.accessors = <PropertyAccessorElement>[getterG];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.mixins = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(getterName), same(getterG));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[getterName], same(getterG));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -282,9 +283,9 @@
void test_getMapOfMembersInheritedFromInterfaces_implicitExtends() {
// class A {}
ClassElementImpl classA = ElementFactory.classElement2("A");
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
_assertNoErrors(classA);
}
@@ -304,10 +305,10 @@
classI2.accessors = <PropertyAccessorElement>[getter];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI2.type, classI1.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapA.get(methodName), isNull);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapA[methodName], isNull);
_assertErrors(classA,
[StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD]);
}
@@ -328,10 +329,10 @@
classI2.methods = <MethodElement>[methodM2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapA.get(methodName), isNull);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapA[methodName], isNull);
_assertErrors(
classA, [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]);
}
@@ -352,10 +353,10 @@
classI2.accessors = <PropertyAccessorElement>[getter];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapA.get(methodName), isNull);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapA[methodName], isNull);
_assertErrors(classA,
[StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD]);
}
@@ -402,10 +403,10 @@
classI2.methods = <MethodElement>[methodM2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapA.get(methodName), isNull);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapA[methodName], isNull);
_assertErrors(
classA, [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]);
}
@@ -426,10 +427,10 @@
classI2.methods = <MethodElement>[methodM2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI2.type, classI1.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapA.get(methodName), isNull);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapA[methodName], isNull);
_assertErrors(
classA, [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]);
}
@@ -443,13 +444,13 @@
ElementFactory.methodElement(methodName, _typeProvider.intType);
classA.methods = <MethodElement>[methodM];
ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(methodName), same(methodM));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[methodName], same(methodM));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -464,13 +465,13 @@
classA.methods = <MethodElement>[methodM];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.interfaces = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(methodName), same(methodM));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[methodName], same(methodM));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -485,13 +486,13 @@
classA.methods = <MethodElement>[methodM];
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.mixins = <InterfaceType>[classA.type];
- MemberMap mapB =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject);
- expect(mapB.size, _numOfMembersInObject + 1);
- expect(mapB.get(methodName), same(methodM));
+ Map<String, ExecutableElement> mapB =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classB);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject);
+ expect(mapB.length, _numOfMembersInObject + 1);
+ expect(mapB[methodName], same(methodM));
_assertNoErrors(classA);
_assertNoErrors(classB);
}
@@ -512,11 +513,11 @@
classI2.methods = <MethodElement>[methodM2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 2);
- expect(mapA.get(methodName1), same(methodM1));
- expect(mapA.get(methodName2), same(methodM2));
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 2);
+ expect(mapA[methodName1], same(methodM1));
+ expect(mapA[methodName2], same(methodM2));
_assertNoErrors(classA);
}
@@ -536,12 +537,12 @@
classI2.accessors = <PropertyAccessorElement>[getter2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 1);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 1);
PropertyAccessorElement syntheticAccessor = ElementFactory.getterElement(
accessorName, false, _typeProvider.dynamicType);
- expect(mapA.get(accessorName).type, syntheticAccessor.type);
+ expect(mapA[accessorName].type, syntheticAccessor.type);
_assertNoErrors(classA);
}
@@ -571,12 +572,12 @@
classI2.methods = <MethodElement>[methodM2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 1);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 1);
MethodElement syntheticMethod = ElementFactory.methodElement(
methodName, _typeProvider.dynamicType, [_typeProvider.dynamicType]);
- expect(mapA.get(methodName).type, syntheticMethod.type);
+ expect(mapA[methodName].type, syntheticMethod.type);
_assertNoErrors(classA);
}
@@ -596,13 +597,13 @@
classI2.accessors = <PropertyAccessorElement>[setter2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 1);
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 1);
PropertyAccessorElementImpl syntheticAccessor = ElementFactory
.setterElement(accessorName, false, _typeProvider.dynamicType);
syntheticAccessor.returnType = _typeProvider.dynamicType;
- expect(mapA.get("$accessorName=").type, syntheticAccessor.type);
+ expect(mapA["$accessorName="].type, syntheticAccessor.type);
_assertNoErrors(classA);
}
@@ -637,12 +638,12 @@
classI2.type,
classI3.type
];
- MemberMap mapD =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classD);
- expect(mapD.size, _numOfMembersInObject + 1);
+ Map<String, ExecutableElement> mapD =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classD);
+ expect(mapD.length, _numOfMembersInObject + 1);
PropertyAccessorElement syntheticAccessor = ElementFactory.getterElement(
accessorName, false, _typeProvider.dynamicType);
- expect(mapD.get(accessorName).type, syntheticAccessor.type);
+ expect(mapD[accessorName].type, syntheticAccessor.type);
_assertNoErrors(classD);
}
@@ -692,12 +693,12 @@
classI2.type,
classI3.type
];
- MemberMap mapD =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classD);
- expect(mapD.size, _numOfMembersInObject + 1);
+ Map<String, ExecutableElement> mapD =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classD);
+ expect(mapD.length, _numOfMembersInObject + 1);
MethodElement syntheticMethod = ElementFactory.methodElement(
methodName, _typeProvider.dynamicType, [_typeProvider.dynamicType]);
- expect(mapD.get(methodName).type, syntheticMethod.type);
+ expect(mapD[methodName].type, syntheticMethod.type);
_assertNoErrors(classD);
}
@@ -732,13 +733,13 @@
classI2.type,
classI3.type
];
- MemberMap mapD =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classD);
- expect(mapD.size, _numOfMembersInObject + 1);
+ Map<String, ExecutableElement> mapD =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classD);
+ expect(mapD.length, _numOfMembersInObject + 1);
PropertyAccessorElementImpl syntheticAccessor = ElementFactory
.setterElement(accessorName, false, _typeProvider.dynamicType);
syntheticAccessor.returnType = _typeProvider.dynamicType;
- expect(mapD.get("$accessorName=").type, syntheticAccessor.type);
+ expect(mapD["$accessorName="].type, syntheticAccessor.type);
_assertNoErrors(classD);
}
@@ -763,10 +764,10 @@
classI2.methods = <MethodElement>[methodM2];
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 1);
- expect(mapA.get(methodName), same(methodM2));
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 1);
+ expect(mapA[methodName], same(methodM2));
_assertNoErrors(classA);
}
@@ -809,10 +810,10 @@
classI2.type,
classI3.type
];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 1);
- expect(mapA.get(methodName), same(methodM3));
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 1);
+ expect(mapA[methodName], same(methodM3));
_assertNoErrors(classA);
}
@@ -861,10 +862,10 @@
classI3.type,
classI4.type
];
- MemberMap mapA =
- _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
- expect(mapA.size, _numOfMembersInObject + 1);
- expect(mapA.get(methodName), same(methodM4));
+ Map<String, ExecutableElement> mapA =
+ _inheritanceManager.getMembersInheritedFromInterfaces(classA);
+ expect(mapA.length, _numOfMembersInObject + 1);
+ expect(mapA[methodName], same(methodM4));
_assertNoErrors(classA);
}
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 8b4cd5e..28f721e 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -5581,26 +5581,6 @@
verify([source]);
}
- void test_undefinedIdentifier_hide() {
- Source source = addSource(r'''
-library L;
-export 'lib1.dart' hide a;''');
- addNamedSource("/lib1.dart", "library lib1;");
- computeLibrarySourceErrors(source);
- assertNoErrors(source);
- verify([source]);
- }
-
- void test_undefinedIdentifier_show() {
- Source source = addSource(r'''
-library L;
-export 'lib1.dart' show a;''');
- addNamedSource("/lib1.dart", "library lib1;");
- computeLibrarySourceErrors(source);
- assertNoErrors(source);
- verify([source]);
- }
-
void test_undefinedIdentifier_synthetic_whenExpression() {
Source source = addSource(r'''
print(x) {}
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index c366b84..47be73f 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -2766,12 +2766,6 @@
bool parseAsync = true;
/**
- * A flag indicating whether conditional directives support should be enabled
- * for a specific test.
- */
- bool enableConditionalDirectives = false;
-
- /**
* A flag indicating whether generic method support should be enabled for a
* specific test.
*/
@@ -2833,7 +2827,6 @@
//
Parser parser = createParser(listener);
parser.parseAsync = parseAsync;
- parser.parseConditionalDirectives = enableConditionalDirectives;
parser.parseGenericMethods = enableGenericMethods;
parser.parseGenericMethodComments = enableGenericMethodComments;
parser.parseFunctionBodies = parseFunctionBodies;
@@ -2964,7 +2957,6 @@
Parser parser = createParser(listener);
parser.parseAsync = parseAsync;
parser.parseFunctionBodies = parseFunctionBodies;
- parser.parseConditionalDirectives = enableConditionalDirectives;
parser.parseGenericMethods = enableGenericMethods;
parser.parseGenericMethodComments = enableGenericMethodComments;
CompilationUnit unit = parser.parseCompilationUnit(token);
@@ -3707,7 +3699,7 @@
(obj) => obj is FieldDeclaration, FieldDeclaration, classMember);
VariableDeclarationList fieldList =
(classMember as FieldDeclaration).fields;
- expect((fieldList.keyword as KeywordToken).keyword, Keyword.CONST);
+ expect(fieldList.keyword.keyword, Keyword.CONST);
NodeList<VariableDeclaration> fields = fieldList.variables;
expect(fields, hasLength(1));
VariableDeclaration field = fields[0];
@@ -3733,7 +3725,7 @@
(obj) => obj is FieldDeclaration, FieldDeclaration, classMember);
VariableDeclarationList fieldList =
(classMember as FieldDeclaration).fields;
- expect((fieldList.keyword as KeywordToken).keyword, Keyword.FINAL);
+ expect(fieldList.keyword.keyword, Keyword.FINAL);
NodeList<VariableDeclaration> fields = fieldList.variables;
expect(fields, hasLength(1));
VariableDeclaration field = fields[0];
@@ -3759,7 +3751,7 @@
(obj) => obj is FieldDeclaration, FieldDeclaration, classMember);
VariableDeclarationList fieldList =
(classMember as FieldDeclaration).fields;
- expect((fieldList.keyword as KeywordToken).keyword, Keyword.VAR);
+ expect(fieldList.keyword.keyword, Keyword.VAR);
NodeList<VariableDeclaration> fields = fieldList.variables;
expect(fields, hasLength(1));
VariableDeclaration field = fields[0];
@@ -7262,7 +7254,6 @@
}
void test_parseExportDirective_configuration_multiple() {
- enableConditionalDirectives = true;
ExportDirective directive = parse(
"parseExportDirective",
<Object>[emptyCommentAndMetadata()],
@@ -7277,7 +7268,6 @@
}
void test_parseExportDirective_configuration_single() {
- enableConditionalDirectives = true;
ExportDirective directive = parse(
"parseExportDirective",
<Object>[emptyCommentAndMetadata()],
@@ -7515,7 +7505,7 @@
Token keyword = result.keyword;
expect(keyword, isNotNull);
expect(keyword.type, TokenType.KEYWORD);
- expect((keyword as KeywordToken).keyword, Keyword.CONST);
+ expect(keyword.keyword, Keyword.CONST);
expect(result.type, isNull);
}
@@ -7525,7 +7515,7 @@
Token keyword = result.keyword;
expect(keyword, isNotNull);
expect(keyword.type, TokenType.KEYWORD);
- expect((keyword as KeywordToken).keyword, Keyword.CONST);
+ expect(keyword.keyword, Keyword.CONST);
expect(result.type, isNotNull);
}
@@ -7535,7 +7525,7 @@
Token keyword = result.keyword;
expect(keyword, isNotNull);
expect(keyword.type, TokenType.KEYWORD);
- expect((keyword as KeywordToken).keyword, Keyword.FINAL);
+ expect(keyword.keyword, Keyword.FINAL);
expect(result.type, isNull);
}
@@ -7545,7 +7535,7 @@
Token keyword = result.keyword;
expect(keyword, isNotNull);
expect(keyword.type, TokenType.KEYWORD);
- expect((keyword as KeywordToken).keyword, Keyword.FINAL);
+ expect(keyword.keyword, Keyword.FINAL);
expect(result.type, isNotNull);
}
@@ -7555,7 +7545,7 @@
Token keyword = result.keyword;
expect(keyword, isNotNull);
expect(keyword.type, TokenType.KEYWORD);
- expect((keyword as KeywordToken).keyword, Keyword.FINAL);
+ expect(keyword.keyword, Keyword.FINAL);
expect(result.type, isNotNull);
}
@@ -7600,7 +7590,7 @@
Token keyword = result.keyword;
expect(keyword, isNotNull);
expect(keyword.type, TokenType.KEYWORD);
- expect((keyword as KeywordToken).keyword, Keyword.VAR);
+ expect(keyword.keyword, Keyword.VAR);
expect(result.type, isNull);
}
@@ -8472,7 +8462,6 @@
}
void test_parseImportDirective_configuration_multiple() {
- enableConditionalDirectives = true;
ImportDirective directive = parse(
"parseImportDirective",
<Object>[emptyCommentAndMetadata()],
@@ -8490,7 +8479,6 @@
}
void test_parseImportDirective_configuration_single() {
- enableConditionalDirectives = true;
ImportDirective directive = parse(
"parseImportDirective",
<Object>[emptyCommentAndMetadata()],
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 4fe6516..fd39ad5 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -42,7 +42,6 @@
runReflectiveTests(ErrorResolverTest);
runReflectiveTests(LibraryImportScopeTest);
runReflectiveTests(LibraryScopeTest);
- runReflectiveTests(MemberMapTest);
runReflectiveTests(ScopeTest);
runReflectiveTests(StrictModeTest);
runReflectiveTests(SubtypeManagerTest);
@@ -536,52 +535,6 @@
}
}
-@reflectiveTest
-class MemberMapTest {
- /**
- * The null type.
- */
- InterfaceType _nullType;
-
- void setUp() {
- _nullType = new TestTypeProvider().nullType;
- }
-
- void test_MemberMap_copyConstructor() {
- MethodElement m1 = ElementFactory.methodElement("m1", _nullType);
- MethodElement m2 = ElementFactory.methodElement("m2", _nullType);
- MethodElement m3 = ElementFactory.methodElement("m3", _nullType);
- MemberMap map = new MemberMap();
- map.put(m1.name, m1);
- map.put(m2.name, m2);
- map.put(m3.name, m3);
- MemberMap copy = new MemberMap.from(map);
- expect(copy.size, map.size);
- expect(copy.get(m1.name), m1);
- expect(copy.get(m2.name), m2);
- expect(copy.get(m3.name), m3);
- }
-
- void test_MemberMap_override() {
- MethodElement m1 = ElementFactory.methodElement("m", _nullType);
- MethodElement m2 = ElementFactory.methodElement("m", _nullType);
- MemberMap map = new MemberMap();
- map.put(m1.name, m1);
- map.put(m2.name, m2);
- expect(map.size, 1);
- expect(map.get("m"), m2);
- }
-
- void test_MemberMap_put() {
- MethodElement m1 = ElementFactory.methodElement("m1", _nullType);
- MemberMap map = new MemberMap();
- expect(map.size, 0);
- map.put(m1.name, m1);
- expect(map.size, 1);
- expect(map.get("m1"), m1);
- }
-}
-
class Scope_EnclosedScopeTest_test_define_duplicate extends Scope {
GatheringErrorListener listener;
diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
index 264d393..c63cc85 100644
--- a/pkg/analyzer/test/generated/resolver_test_case.dart
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -756,12 +756,20 @@
String typeParams: '[]',
String typeArgs: '[]',
String typeFormals: '[]'}) {
+ typeParameters(Element element) {
+ if (element is ExecutableElement) {
+ return element.typeParameters;
+ } else if (element is ParameterElement) {
+ return element.typeParameters;
+ }
+ fail('Wrong element type: ${element.runtimeType}');
+ }
SimpleIdentifier identifier = findIdentifier(name);
// Element is either ExecutableElement or ParameterElement.
- var element = identifier.staticElement;
+ Element element = identifier.staticElement;
FunctionTypeImpl functionType = identifier.staticType;
expect(functionType.toString(), type);
- expect(element.typeParameters.toString(), elementTypeParams);
+ expect(typeParameters(element).toString(), elementTypeParams);
expect(functionType.typeParameters.toString(), typeParams);
expect(functionType.typeArguments.toString(), typeArgs);
expect(functionType.typeFormals.toString(), typeFormals);
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 64bebe3..4568fe9 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -470,7 +470,49 @@
''');
}
- void test_illegal_return_type_async_function() {
+ void test_illegalAsyncGeneratorReturnType_function_nonStream() {
+ assertErrorsInCode(
+ '''
+int f() async* {}
+''',
+ [StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE]);
+ }
+
+ void test_illegalAsyncGeneratorReturnType_function_subtypeOfStream() {
+ resetWithOptions(new AnalysisOptionsImpl()..strongMode = true);
+ assertErrorsInCode(
+ '''
+import 'dart:async';
+abstract class SubStream<T> implements Stream<T> {}
+SubStream<int> f() async* {}
+''',
+ [StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE]);
+ }
+
+ void test_illegalAsyncGeneratorReturnType_method_nonStream() {
+ assertErrorsInCode(
+ '''
+class C {
+ int f() async* {}
+}
+''',
+ [StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE]);
+ }
+
+ void test_illegalAsyncGeneratorReturnType_method_subtypeOfStream() {
+ resetWithOptions(new AnalysisOptionsImpl()..strongMode = true);
+ assertErrorsInCode(
+ '''
+import 'dart:async';
+abstract class SubStream<T> implements Stream<T> {}
+class C {
+ SubStream<int> f() async* {}
+}
+''',
+ [StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE]);
+ }
+
+ void test_illegalAsyncReturnType_function_nonFuture() {
assertErrorsInCode(
'''
int f() async {}
@@ -481,29 +523,24 @@
]);
}
- void test_illegal_return_type_async_generator_function() {
+ void test_illegalAsyncReturnType_function_subtypeOfFuture() {
+ resetWithOptions(new AnalysisOptionsImpl()..strongMode = true);
assertErrorsInCode(
'''
-int f() async* {}
-''',
- [StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE]);
- }
-
- void test_illegal_return_type_async_generator_method() {
- assertErrorsInCode(
- '''
-class C {
- int f() async* {}
+import 'dart:async';
+abstract class SubFuture<T> implements Future<T> {}
+SubFuture<int> f() async {
+ return 0;
}
''',
- [StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE]);
+ [StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE]);
}
- void test_illegal_return_type_async_method() {
+ void test_illegalAsyncReturnType_method_nonFuture() {
assertErrorsInCode(
'''
class C {
- int f() async {}
+ int m() async {}
}
''',
[
@@ -512,7 +549,22 @@
]);
}
- void test_illegal_return_type_sync_generator_function() {
+ void test_illegalAsyncReturnType_method_subtypeOfFuture() {
+ resetWithOptions(new AnalysisOptionsImpl()..strongMode = true);
+ assertErrorsInCode(
+ '''
+import 'dart:async';
+abstract class SubFuture<T> implements Future<T> {}
+class C {
+ SubFuture<int> m() async {
+ return 0;
+ }
+}
+''',
+ [StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE]);
+ }
+
+ void test_illegalSyncGeneratorReturnType_function_nonIterator() {
assertErrorsInCode(
'''
int f() sync* {}
@@ -520,7 +572,17 @@
[StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE]);
}
- void test_illegal_return_type_sync_generator_method() {
+ void test_illegalSyncGeneratorReturnType_function_subclassOfIterator() {
+ resetWithOptions(new AnalysisOptionsImpl()..strongMode = true);
+ assertErrorsInCode(
+ '''
+abstract class SubIterator<T> implements Iterator<T> {}
+SubIterator<int> f() sync* {}
+''',
+ [StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE]);
+ }
+
+ void test_illegalSyncGeneratorReturnType_method_nonIterator() {
assertErrorsInCode(
'''
class C {
@@ -530,6 +592,18 @@
[StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE]);
}
+ void test_illegalSyncGeneratorReturnType_method_subclassOfIterator() {
+ resetWithOptions(new AnalysisOptionsImpl()..strongMode = true);
+ assertErrorsInCode(
+ '''
+abstract class SubIterator<T> implements Iterator<T> {}
+class C {
+ SubIterator<int> f() sync* {}
+}
+''',
+ [StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE]);
+ }
+
void test_inconsistentMethodInheritance_paramCount() {
assertErrorsInCode(
r'''
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 8a55212..7bc5ed1 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -681,6 +681,41 @@
verify([source]);
}
+ void test_inferredFieldDeclaration_propagation() {
+ // Regression test for https://github.com/dart-lang/sdk/issues/25546
+ String code = r'''
+ abstract class A {
+ Map<int, List<int>> get map;
+ }
+ class B extends A {
+ var map = { 42: [] };
+ }
+ class C extends A {
+ get map => { 43: [] };
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+ Asserter<InterfaceType> assertMapOfIntToListOfInt =
+ _isMapOf(_isInt, assertListOfInt);
+
+ VariableDeclaration mapB = AstFinder.getFieldInClass(unit, "B", "map");
+ MethodDeclaration mapC = AstFinder.getMethodInClass(unit, "C", "map");
+ assertMapOfIntToListOfInt(mapB.element.type);
+ assertMapOfIntToListOfInt(mapC.element.returnType);
+
+ MapLiteral mapLiteralB = mapB.initializer;
+ MapLiteral mapLiteralC = (mapC.body as ExpressionFunctionBody).expression;
+ assertMapOfIntToListOfInt(mapLiteralB.staticType);
+ assertMapOfIntToListOfInt(mapLiteralC.staticType);
+
+ ListLiteral listLiteralB = mapLiteralB.entries[0].value;
+ ListLiteral listLiteralC = mapLiteralC.entries[0].value;
+ assertListOfInt(listLiteralB.staticType);
+ assertListOfInt(listLiteralC.staticType);
+ }
+
void test_instanceCreation() {
String code = r'''
class A<S, T> {
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 62d0beb..e7021f0 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -8,8 +8,7 @@
import 'package:analyzer/file_system/memory_file_system.dart' as resource;
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/engine.dart'
- show AnalysisEngine, ChangeSet;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/test/src/summary/index_unit_test.dart b/pkg/analyzer/test/src/summary/index_unit_test.dart
index cb18d02..9a269b0 100644
--- a/pkg/analyzer/test/src/summary/index_unit_test.dart
+++ b/pkg/analyzer/test/src/summary/index_unit_test.dart
@@ -819,6 +819,26 @@
..isInvokedAt('foo());', false);
}
+ void test_isReferencedBy_FunctionElement_with_LibraryElement() {
+ addSource(
+ '/foo.dart',
+ r'''
+bar() {}
+''');
+ _indexTestUnit('''
+import "foo.dart";
+main() {
+ bar();
+}
+''');
+ LibraryElement fooLibrary = testLibraryElement.imports[0].importedLibrary;
+ assertThat(fooLibrary)..isReferencedAt('"foo.dart";', true, length: 10);
+ {
+ FunctionElement bar = fooLibrary.definingCompilationUnit.functions[0];
+ assertThat(bar)..isInvokedAt('bar();', false);
+ }
+ }
+
void test_isReferencedBy_FunctionTypeAliasElement() {
_indexTestUnit('''
typedef A();
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index 81499ae..e5f0dfa 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_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 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/link.dart';
import 'package:unittest/unittest.dart';
@@ -38,6 +39,117 @@
return linker.getLibrary(Uri.parse(uri));
}
+ void test_baseClass_genericWithAccessor() {
+ createLinker('''
+class B<T> {
+ int get i => null;
+}
+class C<U> extends B<U> {
+ var j;
+}
+ ''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_baseClass_genericWithField() {
+ createLinker('''
+class B<T> {
+ int i = 0;
+}
+class C<T> extends B<T> {
+ void f() {}
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_baseClass_genericWithFunctionTypedParameter() {
+ createLinker('''
+class B<T> {
+ void f(void g(T t));
+}
+class C<U> extends B<U> {
+ void f(g) {}
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_baseClass_genericWithGenericMethod() {
+ createLinker('''
+class B<T> {
+ List<U> f<U>(U u) => null;
+}
+class C<V> extends B<V> {
+ var j;
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_baseClass_genericWithGenericMethod_returnsGenericFuture() {
+ createLinker('''
+import 'dart:async';
+class B<T> {
+ Future<T> f() => null;
+}
+class C<T> extends B<T> {
+ Future<T> f() => null;
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_baseClass_genericWithStaticFinal() {
+ createLinker('''
+class B<T> {
+ static final int i = 0;
+}
+class C<T> extends B<T> {
+ void f() {}
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ }
+
+ void test_baseClass_withPrivateField() {
+ createLinker('''
+class B {
+ var _b;
+}
+class C extends B {
+ var c;
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_constCycle_viaLength() {
+ createLinker('''
+class C {
+ final y;
+ const C() : y = x.length;
+}
+const x = [const C()];
+''');
+ testLibrary.libraryCycleForLink.ensureLinked();
+ ClassElementForLink classC = testLibrary.getContainedName('C');
+ expect(classC.unnamedConstructor.isCycleFree, false);
+ }
+
void test_inferredType_instanceField_dynamic() {
createLinker('''
var x;
@@ -87,6 +199,22 @@
expect(cls.methods[0].returnType.toString(), 'dynamic');
}
+ void test_inferredType_methodReturnType_void() {
+ createLinker('''
+class B {
+ void f() {}
+}
+class C extends B {
+ f() {}
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ ClassElementForLink_Class cls = library.getContainedName('C');
+ expect(cls.methods, hasLength(1));
+ expect(cls.methods[0].returnType.toString(), 'void');
+ }
+
void test_inferredType_staticField_dynamic() {
createLinker('''
dynamic x = null;
@@ -100,6 +228,7 @@
.getContainedName('C')
.getContainedName('y')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'dynamic');
@@ -115,6 +244,7 @@
.getLibrary(linkerInputs.testDartUri)
.getContainedName('y')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'dynamic');
@@ -137,6 +267,7 @@
library
.getContainedName('z')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'dynamic');
@@ -160,11 +291,32 @@
library
.getContainedName('x')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'int');
}
+ void test_inferredTypeFromOutsideBuildUnit_instanceField_toInstanceField() {
+ var bundle = createPackageBundle(
+ '''
+class C {
+ var f = 0; // Inferred type: int
+}
+''',
+ path: '/a.dart');
+ addBundle(bundle);
+ createLinker('''
+import 'a.dart';
+class D {
+ var g = new C().f; // Inferred type: int
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ ClassElementForLink_Class classD = library.getContainedName('D');
+ expect(classD.fields[0].inferredType.toString(), 'int');
+ }
+
void test_inferredTypeFromOutsideBuildUnit_methodParamType_viaGeneric() {
var bundle = createPackageBundle(
'''
@@ -186,27 +338,12 @@
library
.getContainedName('x')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'int');
}
- void test_inferredType_methodReturnType_void() {
- createLinker('''
-class B {
- void f() {}
-}
-class C extends B {
- f() {}
-}
-''');
- LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
- library.libraryCycleForLink.ensureLinked();
- ClassElementForLink_Class cls = library.getContainedName('C');
- expect(cls.methods, hasLength(1));
- expect(cls.methods[0].returnType.toString(), 'void');
- }
-
void test_inferredTypeFromOutsideBuildUnit_methodParamType_viaInheritance() {
var bundle = createPackageBundle(
'''
@@ -255,6 +392,7 @@
library
.getContainedName('x')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'int');
@@ -295,6 +433,7 @@
.getLibrary(linkerInputs.testDartUri)
.getContainedName('x')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'int');
@@ -309,6 +448,7 @@
.getLibrary(linkerInputs.testDartUri)
.getContainedName('b')
.asTypeInferenceNode
+ .variableElement
.inferredType
.toString(),
'int');
@@ -397,4 +537,50 @@
unorderedEquals([libA.libraryCycleForLink, libB.libraryCycleForLink]));
expect(libraryCycle.libraries, [testLibrary]);
}
+
+ void test_multiplyInheritedExecutable_differentSignatures() {
+ createLinker('''
+class B {
+ void f() {}
+}
+abstract class I {
+ f();
+}
+class C extends B with I {}
+class D extends C {
+ void f() {}
+}
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ library.libraryCycleForLink.ensureLinked();
+ // No assertions--just make sure it doesn't crash.
+ }
+
+ void test_parameterParentElementForLink_implicitFunctionTypeIndices() {
+ createLinker('void f(a, void g(b, c, d, void h())) {}');
+ TopLevelFunctionElementForLink f = testLibrary.getContainedName('f');
+ expect(f.implicitFunctionTypeIndices, []);
+ ParameterElementForLink g = f.parameters[1];
+ FunctionType gType = g.type;
+ FunctionElementForLink_FunctionTypedParam gTypeElement = gType.element;
+ expect(gTypeElement.implicitFunctionTypeIndices, [1]);
+ ParameterElementForLink h = gTypeElement.parameters[3];
+ FunctionType hType = h.type;
+ FunctionElementForLink_FunctionTypedParam hTypeElement = hType.element;
+ expect(hTypeElement.implicitFunctionTypeIndices, [1, 3]);
+ }
+
+ void test_parameterParentElementForLink_innermostExecutable() {
+ createLinker('void f(void g(void h())) {}');
+ TopLevelFunctionElementForLink f = testLibrary.getContainedName('f');
+ expect(f.innermostExecutable, same(f));
+ ParameterElementForLink g = f.parameters[0];
+ FunctionType gType = g.type;
+ FunctionElementForLink_FunctionTypedParam gTypeElement = gType.element;
+ expect(gTypeElement.innermostExecutable, same(f));
+ ParameterElementForLink h = gTypeElement.parameters[0];
+ FunctionType hType = h.type;
+ FunctionElementForLink_FunctionTypedParam hTypeElement = hType.element;
+ expect(hTypeElement.innermostExecutable, same(f));
+ }
}
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
index f2f1a82..b4a2172 100644
--- a/pkg/analyzer/test/src/summary/prelinker_test.dart
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -59,6 +59,8 @@
@override
void serializeLibraryElement(LibraryElement library) {
super.serializeLibraryElement(library);
+ uriToPublicNamespace[library.source.uri.toString()] =
+ unlinkedUnits[0].publicNamespace;
Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
expect(unlinkedUnits.length, unitUris.length);
for (int i = 1; i < unlinkedUnits.length; i++) {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 5e2bcd6..9d7a10d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -245,10 +245,87 @@
''');
}
+ void test_infer_extractProperty_getter_sequence() {
+ var unit = checkFile(r'''
+class A {
+ B b = new B();
+}
+class B {
+ C c = new C();
+}
+class C {
+ int d;
+}
+var a = new A();
+var v = a.b.c.d;
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'int');
+ }
+
+ void test_infer_extractProperty_getter_sequence_generic() {
+ var unit = checkFile(r'''
+class A<T> {
+ B<T> b = new B<T>();
+}
+class B<K> {
+ C<List<K>, int> c = new C<List<K>, int>();
+}
+class C<K, V> {
+ Map<K, V> d;
+}
+var a = new A<double>();
+var v = a.b.c.d;
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'Map<List<double>, int>');
+ }
+
+ void test_infer_extractProperty_getter_sequence_withUnresolved() {
+ var unit = checkFile(r'''
+class A {
+ B b = new B();
+}
+class B {
+ int c;
+}
+var a = new A();
+var v = a.b.foo.c;
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'dynamic');
+ }
+
void test_infer_extractProperty_method() {
- checkFile(r'''
+ var unit = checkFile(r'''
+class A {
+ int m(double p1, String p2) => 42;
+}
+var a = new A();
+var v = a.m;
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), '(double, String) → int');
+ }
+
+ void test_infer_extractProperty_method2() {
+ var unit = checkFile(r'''
var a = 1.round;
''');
+ expect(unit.topLevelVariables[0].type.toString(), '() → int');
+ }
+
+ void test_infer_extractProperty_method_sequence() {
+ var unit = checkFile(r'''
+class A {
+ B b = new B();
+}
+class B {
+ C c = new C();
+}
+class C {
+ int m(double p1, String p2) => 42;
+}
+var a = new A();
+var v = a.b.c.m;
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), '(double, String) → int');
}
void test_infer_invokeConstructor_factoryRedirected() {
@@ -319,6 +396,160 @@
''');
}
+ void test_infer_invokeMethodRef_function() {
+ var unit = checkFile(r'''
+int m() => 0;
+var a = m();
+ ''');
+ expect(unit.topLevelVariables[0].type.toString(), 'int');
+ }
+
+ void test_infer_invokeMethodRef_function_generic() {
+ var unit = checkFile(r'''
+/*=Map<int, V>*/ m/*<V>*/(/*=V*/ a) => null;
+var a = m(2.3);
+ ''');
+ expect(unit.topLevelVariables[0].type.toString(), 'Map<int, double>');
+ }
+
+ void test_infer_invokeMethodRef_function_importedWithPrefix() {
+ addFile(
+ r'''
+int m() => 0;
+''',
+ name: '/a.dart');
+ var unit = checkFile(r'''
+import 'a.dart' as p;
+var a = p.m();
+ ''');
+ expect(unit.topLevelVariables[0].type.toString(), 'int');
+ }
+
+ void test_infer_invokeMethodRef_method() {
+ var unit = checkFile(r'''
+class A {
+ int m() => 0;
+}
+var a = new A();
+var b = a.m();
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'int');
+ }
+
+ void test_infer_invokeMethodRef_method_g() {
+ var unit = checkFile(r'''
+class A {
+ /*=T*/ m/*<T>*/(/*=T*/ a) => null;
+}
+var a = new A();
+var b = a.m(1.0);
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'double');
+ }
+
+ void test_infer_invokeMethodRef_method_genericSequence() {
+ var unit = checkFile(r'''
+class A<T> {
+ B<T> b = new B<T>();
+}
+class B<K> {
+ C<List<K>, int> c = new C<List<K>, int>();
+}
+class C<K, V> {
+ Map<K, V> m() => null;
+}
+var a = new A<double>();
+var v = a.b.c.m();
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'Map<List<double>, int>');
+ }
+
+ void test_infer_invokeMethodRef_method_gg() {
+ var unit = checkFile(r'''
+class A<K> {
+ /*=Map<K, V>*/ m/*<V>*/(/*=V*/ a) => null;
+}
+var a = new A<int>();
+var b = a.m(1.0);
+ ''');
+ expect(unit.topLevelVariables[1].type.toString(), 'Map<int, double>');
+ }
+
+ void test_infer_invokeMethodRef_method_importedWithPrefix() {
+ addFile(
+ r'''
+class A {
+ int m() => 0;
+}
+var a = new A();
+''',
+ name: '/a.dart');
+ var unit = checkFile(r'''
+import 'a.dart' as p;
+var b = p.a.m();
+ ''');
+ expect(unit.topLevelVariables[0].type.toString(), 'int');
+ }
+
+ void test_infer_invokeMethodRef_method_importedWithPrefix2() {
+ addFile(
+ r'''
+class A {
+ B b = new B();
+}
+class B {
+ int m() => 0;
+}
+var a = new A();
+''',
+ name: '/a.dart');
+ var unit = checkFile(r'''
+import 'a.dart' as p;
+var b = p.a.b.m();
+ ''');
+ expect(unit.topLevelVariables[0].type.toString(), 'int');
+ }
+
+ void test_infer_invokeMethodRef_method_withInferredTypeInLibraryCycle() {
+ var unit = checkFile('''
+class Base {
+ int m() => 0;
+}
+class A extends Base {
+ m() => 0; // Inferred return type: int
+}
+var a = new A();
+var b = a.m();
+ ''');
+ // Type inference operates on static and top level variables prior to
+ // instance members. So at the time `b` is inferred, `A.m` still has return
+ // type `dynamic`.
+ expect(unit.topLevelVariables[1].type.toString(), 'dynamic');
+ }
+
+ void test_infer_invokeMethodRef_method_withInferredTypeOutsideLibraryCycle() {
+ addFile(
+ '''
+class Base {
+ int m() => 0;
+}
+class A extends Base {
+ m() => 0; // Inferred return type: int
+}
+''',
+ name: '/a.dart');
+ var unit = checkFile('''
+import 'a.dart';
+var a = new A();
+var b = a.m();
+''');
+ // Since a.dart is in a separate library file from the compilation unit
+ // containing `a` and `b`, its types are inferred first; then `a` and `b`'s
+ // types are inferred. So the inferred return type of `int` should be
+ // propagated to `b`.
+ expect(unit.topLevelVariables[1].type.toString(), 'int');
+ }
+
@override
@failingTest
void test_inferCorrectlyOnMultipleVariablesDeclaredTogether() {
@@ -331,30 +562,6 @@
super.test_inferenceInCyclesIsDeterministic();
}
- @override
- @failingTest
- void test_inferFromRhsOnlyIfItWontConflictWithOverriddenFields() {
- super.test_inferFromRhsOnlyIfItWontConflictWithOverriddenFields();
- }
-
- @override
- @failingTest
- void test_inferTypesOnGenericInstantiations_4() {
- super.test_inferTypesOnGenericInstantiations_4();
- }
-
- @override
- @failingTest
- void test_inferTypesOnGenericInstantiations_5() {
- super.test_inferTypesOnGenericInstantiations_5();
- }
-
- @override
- @failingTest
- void test_inferTypesOnGenericInstantiationsInLibraryCycle() {
- super.test_inferTypesOnGenericInstantiationsInLibraryCycle();
- }
-
void test_invokeMethod_notGeneric_genericClass() {
var unit = checkFile(r'''
class C<T> {
@@ -410,12 +617,13 @@
bool get checkPropagatedTypes => false;
@override
- void checkLibrary(String text,
+ LibraryElementImpl checkLibrary(String text,
{bool allowErrors: false, bool dumpSummaries: false}) {
Source source = addTestSource(text);
LibraryElementImpl resynthesized = _encodeDecodeLibraryElement(source);
LibraryElementImpl original = context.computeLibraryElement(source);
checkLibraryElements(original, resynthesized);
+ return resynthesized;
}
@override
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 5b4f8ed..b4e87cd 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -17,8 +17,7 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/resolver.dart'
- show Namespace, TypeProvider;
+import 'package:analyzer/src/generated/resolver.dart' show Namespace;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/ast_factory.dart';
@@ -1212,7 +1211,7 @@
@reflectiveTest
class ResynthesizeElementTest extends ResynthesizeTest {
@override
- void checkLibrary(String text,
+ LibraryElementImpl checkLibrary(String text,
{bool allowErrors: false, bool dumpSummaries: false}) {
Source source = addTestSource(text);
LibraryElementImpl original = context.computeLibraryElement(source);
@@ -1222,6 +1221,7 @@
source.uri.toString(),
original);
checkLibraryElements(original, resynthesized);
+ return resynthesized;
}
@override
@@ -1317,7 +1317,7 @@
@reflectiveTest
abstract class ResynthesizeTest extends AbstractResynthesizeTest {
- void checkLibrary(String text,
+ LibraryElementImpl checkLibrary(String text,
{bool allowErrors: false, bool dumpSummaries: false});
/**
@@ -3165,6 +3165,18 @@
checkLibrary('import "a.dart" as a; a.C c;');
}
+ test_import_self() {
+ LibraryElementImpl resynthesized = checkLibrary('''
+import 'test.dart' as p;
+class C {}
+class D extends p.C {} // Prevent "unused import" warning
+''');
+ expect(resynthesized.imports, hasLength(2));
+ expect(resynthesized.imports[0].importedLibrary.location,
+ resynthesized.location);
+ expect(resynthesized.imports[1].importedLibrary.isDartCore, true);
+ }
+
test_import_show() {
addLibrary('dart:async');
checkLibrary('''
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index cfde5e9..c50e33b 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -7272,6 +7272,27 @@
expectedPrefix: 'p');
}
+ test_import_self() {
+ if (!checkAstDerivedData) {
+ // TODO(paulberry): this test fails when building the summary from the
+ // element model because the element model can't tell the difference
+ // between self references via a local name and self references via a
+ // self-import.
+ return;
+ }
+ serializeLibraryText('''
+import 'test.dart' as p;
+class C {}
+class D extends p.C {} // Prevent "unused import" warning
+''');
+ expect(unlinkedUnits[0].imports[0].uri, 'test.dart');
+ checkDependency(
+ linked.importDependencies[0], absUri('/test.dart'), 'test.dart');
+ checkTypeRef(unlinkedUnits[0].classes[1].supertype, absUri('/test.dart'),
+ 'test.dart', 'C',
+ expectedPrefix: 'p');
+ }
+
test_import_show_order() {
String libraryText =
'import "dart:async" show Future, Stream; Future x; Stream y;';
@@ -7298,6 +7319,21 @@
expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
}
+ test_inferred_type_keeps_leading_dynamic() {
+ if (!strongMode || skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedClass cls =
+ serializeClassText('class C { final x = <dynamic, int>{}; }');
+ EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
+ // Check that x has inferred type `Map<dynamic, int>`.
+ checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'Map',
+ allowTypeArguments: true, numTypeParameters: 2);
+ expect(type.typeArguments, hasLength(2));
+ checkLinkedTypeRef(type.typeArguments[0], null, null, 'dynamic');
+ checkLinkedTypeRef(type.typeArguments[1], 'dart:core', 'dart:core', 'int');
+ }
+
test_inferred_type_refers_to_bound_type_param() {
if (!strongMode || skipFullyLinkedData) {
return;
@@ -7435,6 +7471,32 @@
checkReferenceIndex(linkedReference.containingReference, null, null, 'D');
}
+ test_inferred_type_skips_trailing_dynamic() {
+ if (!strongMode || skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedClass cls =
+ serializeClassText('class C { final x = <int, dynamic>{}; }');
+ EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
+ // Check that x has inferred type `Map<int>`. The trailing type argument
+ // `dynamic` is omitted.
+ checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'Map',
+ allowTypeArguments: true, numTypeParameters: 2);
+ expect(type.typeArguments, hasLength(1));
+ checkLinkedTypeRef(type.typeArguments[0], 'dart:core', 'dart:core', 'int');
+ }
+
+ test_inferred_type_skips_unnecessary_dynamic() {
+ if (!strongMode || skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedClass cls = serializeClassText('class C { final x = []; }');
+ EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
+ // Check that x has inferred type `List`, not `List<dynamic>`.
+ checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'List',
+ numTypeParameters: 1);
+ }
+
test_initializer_executable_with_bottom_return_type() {
// The synthetic executable for `v` has type `() => Bottom`.
UnlinkedVariable variable = serializeVariableText('int v = null;');
@@ -7744,6 +7806,89 @@
]);
}
+ test_metadata_constructor_call_named_prefixed_unresolved_class() {
+ addNamedSource('/foo.dart', '');
+ UnlinkedClass cls = serializeClassText(
+ 'import "foo.dart" as foo; @foo.A.named() class C {}',
+ allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'named',
+ expectedKind: ReferenceKind.unresolved,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.unresolved, 'A'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'foo')
+ ],
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
+ test_metadata_constructor_call_named_prefixed_unresolved_constructor() {
+ addNamedSource('/foo.dart', 'class A {}');
+ UnlinkedClass cls = serializeClassText(
+ 'import "foo.dart" as foo; @foo.A.named() class C {}',
+ allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'named',
+ expectedKind: ReferenceKind.unresolved,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'A',
+ absoluteUri: absUri('/foo.dart'), relativeUri: 'foo.dart'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'foo')
+ ],
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
+ test_metadata_constructor_call_named_unresolved_class() {
+ UnlinkedClass cls =
+ serializeClassText('@A.named() class C {}', allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'named',
+ expectedKind: ReferenceKind.unresolved,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.unresolved, 'A')
+ ],
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
+ test_metadata_constructor_call_named_unresolved_constructor() {
+ UnlinkedClass cls = serializeClassText('class A {} @A.named() class C {}',
+ allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'named',
+ expectedKind: ReferenceKind.unresolved,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'A')
+ ],
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
test_metadata_constructor_call_unnamed() {
UnlinkedClass cls =
serializeClassText('class A { const A(); } @A() class C {}');
@@ -7775,6 +7920,41 @@
]);
}
+ test_metadata_constructor_call_unnamed_prefixed_unresolved() {
+ addNamedSource('/foo.dart', '');
+ UnlinkedClass cls = serializeClassText(
+ 'import "foo.dart" as foo; @foo.A() class C {}',
+ allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'A',
+ expectedKind: ReferenceKind.unresolved,
+ expectedPrefix: 'foo',
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
+ test_metadata_constructor_call_unnamed_unresolved() {
+ UnlinkedClass cls =
+ serializeClassText('@A() class C {}', allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.invokeConstructor,
+ ], ints: [
+ 0,
+ 0
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'A',
+ expectedKind: ReferenceKind.unresolved,
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
test_metadata_constructor_call_with_args() {
UnlinkedClass cls =
serializeClassText('class A { const A(x); } @A(null) class C {}');
@@ -7943,6 +8123,22 @@
]);
}
+ test_metadata_prefixed_variable_unresolved() {
+ addNamedSource('/a.dart', '');
+ UnlinkedClass cls = serializeClassText(
+ 'import "a.dart" as a; @a.b class C {}',
+ allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'b',
+ expectedKind: ReferenceKind.unresolved,
+ expectedPrefix: 'a',
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
test_metadata_simpleFormalParameter() {
checkAnnotationA(serializeExecutableText('const a = null; f(@a x) {}')
.parameters[0]
@@ -7987,6 +8183,18 @@
.annotations);
}
+ test_metadata_variable_unresolved() {
+ UnlinkedClass cls = serializeClassText('@a class C {}', allowErrors: true);
+ expect(cls.annotations, hasLength(1));
+ _assertUnlinkedConst(cls.annotations[0], operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'a',
+ expectedKind: ReferenceKind.unresolved,
+ checkAstDerivedDataOverride: true)
+ ]);
+ }
+
test_method_documented() {
String text = '''
class C {
@@ -8197,6 +8405,23 @@
expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
}
+ test_reference_zero() {
+ // Element zero of the references table should be populated in a standard
+ // way.
+ serializeLibraryText('');
+ UnlinkedReference unlinkedReference0 = unlinkedUnits[0].references[0];
+ expect(unlinkedReference0.name, '');
+ expect(unlinkedReference0.prefixReference, 0);
+ LinkedReference linkedReference0 = linked.units[0].references[0];
+ expect(linkedReference0.containingReference, 0);
+ expect(linkedReference0.dependency, 0);
+ expect(linkedReference0.kind, ReferenceKind.unresolved);
+ expect(linkedReference0.localIndex, 0);
+ expect(linkedReference0.name, '');
+ expect(linkedReference0.numTypeParameters, 0);
+ expect(linkedReference0.unit, 0);
+ }
+
test_setter_documented() {
String text = '''
// Extra comment so doc comment offset != 0
diff --git a/pkg/analyzer/test/src/summary/test_all.dart b/pkg/analyzer/test/src/summary/test_all.dart
index fa620fe..2f9202b 100644
--- a/pkg/analyzer/test/src/summary/test_all.dart
+++ b/pkg/analyzer/test/src/summary/test_all.dart
@@ -11,6 +11,7 @@
import 'in_summary_source_test.dart' as in_summary_source_test;
import 'incremental_cache_test.dart' as incremental_cache_test;
import 'index_unit_test.dart' as index_unit_test;
+import 'linker_test.dart' as linker_test;
import 'name_filter_test.dart' as name_filter_test;
import 'prelinker_test.dart' as prelinker_test;
import 'resynthesize_ast_test.dart' as resynthesize_ast_test;
@@ -29,6 +30,7 @@
in_summary_source_test.main();
incremental_cache_test.main();
index_unit_test.main();
+ linker_test.main();
name_filter_test.main();
prelinker_test.main();
resynthesize_ast_test.main();
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 9b058bc..4c3007b 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -3202,7 +3202,7 @@
_performParseTask(r'''
part of lib;
class B {}''');
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
@@ -3212,6 +3212,7 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.PART);
expect(outputs[UNITS], hasLength(1));
+ expect(outputs[REFERENCED_SOURCES], hasLength(2));
}
test_perform_computeSourceKind_noDirectives_hasContainingLibrary() {
@@ -3236,7 +3237,7 @@
test_perform_doesNotExist() {
_performParseTask(null);
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
@@ -3246,6 +3247,7 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(1));
+ expect(outputs[REFERENCED_SOURCES], hasLength(2));
}
test_perform_enableAsync_false() {
@@ -3255,7 +3257,7 @@
_performParseTask(r'''
import 'dart:async';
class B {void foo() async {}}''');
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3265,13 +3267,14 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(1));
+ expect(outputs[REFERENCED_SOURCES], hasLength(3));
}
test_perform_enableAsync_true() {
_performParseTask(r'''
import 'dart:async';
class B {void foo() async {}}''');
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3281,6 +3284,7 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(1));
+ expect(outputs[REFERENCED_SOURCES], hasLength(3));
}
test_perform_flushTokenStream() {
@@ -3298,7 +3302,7 @@
export '${a}lib3.dart';
part 'part.dart';
class A {}''');
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3308,6 +3312,7 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(2));
+ expect(outputs[REFERENCED_SOURCES], hasLength(4));
}
test_perform_library() {
@@ -3317,7 +3322,7 @@
export 'lib3.dart';
part 'part.dart';
class A {''');
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(1));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3327,6 +3332,7 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(2));
+ expect(outputs[REFERENCED_SOURCES], hasLength(5));
}
test_perform_library_selfReferenceAsPart() {
@@ -3341,7 +3347,7 @@
_performParseTask(r'''
part of lib;
class B {}''');
- expect(outputs, hasLength(9));
+ expect(outputs, hasLength(10));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
@@ -3351,6 +3357,7 @@
expect(outputs[PARSED_UNIT], isNotNull);
expect(outputs[SOURCE_KIND], SourceKind.PART);
expect(outputs[UNITS], hasLength(1));
+ expect(outputs[REFERENCED_SOURCES], hasLength(2));
}
void _performParseTask(String content) {
diff --git a/pkg/analyzer/test/src/task/dart_work_manager_test.dart b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
index c6d3f1d..cb8fb46 100644
--- a/pkg/analyzer/test/src/task/dart_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/src/dart/scanner/scanner.dart' show ScannerErrorCode;
import 'package:analyzer/src/generated/engine.dart'
show
- AnalysisErrorInfo,
AnalysisErrorInfoImpl,
CacheState,
ChangeNoticeImpl,
diff --git a/pkg/analyzer/test/src/task/html_test.dart b/pkg/analyzer/test/src/task/html_test.dart
index c8f1f97..a41cc1c 100644
--- a/pkg/analyzer/test/src/task/html_test.dart
+++ b/pkg/analyzer/test/src/task/html_test.dart
@@ -265,7 +265,12 @@
Source source = newSource('/test.html');
Map<String, TaskInput> inputs = ParseHtmlTask.buildInputs(source);
expect(inputs, isNotNull);
- expect(inputs.keys, unorderedEquals([ParseHtmlTask.CONTENT_INPUT_NAME]));
+ expect(
+ inputs.keys,
+ unorderedEquals([
+ ParseHtmlTask.CONTENT_INPUT_NAME,
+ ParseHtmlTask.MODIFICATION_TIME_INPUT
+ ]));
}
test_constructor() {
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 05c5713..880479d 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -67,16 +67,6 @@
expect(analysisOptions.enableAsync, false);
}
- test_configure_enableConditionalDirectives() {
- expect(analysisOptions.enableConditionalDirectives, true);
- configureContext('''
-analyzer:
- language:
- enableConditionalDirectives: true
-''');
- expect(analysisOptions.enableConditionalDirectives, true);
- }
-
test_configure_enableGenericMethods() {
expect(analysisOptions.enableGenericMethods, false);
configureContext('''
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index cff8782..9a7b128 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -737,7 +737,47 @@
test('dynamic functions - closures are not fuzzy', () {
// Regression test for
// https://github.com/dart-lang/sdk/issues/26118
+ // https://github.com/dart-lang/sdk/issues/26156
checkFile('''
+ void takesF(void f(int x)) {}
+
+ typedef void TakesInt(int x);
+
+ void update(_) {}
+ void updateOpt([_]) {}
+ void updateOptNum([num x]) {}
+
+ class A {
+ TakesInt f;
+ A(TakesInt g) {
+ f = update;
+ f = updateOpt;
+ f = updateOptNum;
+ }
+ TakesInt g(bool a, bool b) {
+ if (a) {
+ return update;
+ } else if (b) {
+ return updateOpt;
+ } else {
+ return updateOptNum;
+ }
+ }
+ }
+
+ void test0() {
+ takesF(update);
+ takesF(updateOpt);
+ takesF(updateOptNum);
+ TakesInt f;
+ f = update;
+ f = updateOpt;
+ f = updateOptNum;
+ new A(update);
+ new A(updateOpt);
+ new A(updateOptNum);
+ }
+
void test1() {
void takesF(f(int x)) => null;
takesF((dynamic y) => 3);
@@ -1646,10 +1686,10 @@
l = <int>[i, /*info:DOWN_CAST_IMPLICIT*/n, /*warning:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/s];
}
{
- List l = [i];
- l = [s];
- l = [n];
- l = [i, n, s];
+ List l = /*info:INFERRED_TYPE_LITERAL*/[i];
+ l = /*info:INFERRED_TYPE_LITERAL*/[s];
+ l = /*info:INFERRED_TYPE_LITERAL*/[n];
+ l = /*info:INFERRED_TYPE_LITERAL*/[i, n, s];
}
{
Map<String, int> m = <String, int>{s: i};
@@ -1662,13 +1702,15 @@
// TODO(leafp): We can't currently test for key errors since the
// error marker binds to the entire entry.
{
- Map m = {s: i};
- m = {s: s};
- m = {s: n};
- m = {s: i,
+ Map m = /*info:INFERRED_TYPE_LITERAL*/{s: i};
+ m = /*info:INFERRED_TYPE_LITERAL*/{s: s};
+ m = /*info:INFERRED_TYPE_LITERAL*/{s: n};
+ m = /*info:INFERRED_TYPE_LITERAL*/
+ {s: i,
s: n,
s: s};
- m = {i: s,
+ m = /*info:INFERRED_TYPE_LITERAL*/
+ {i: s,
n: s,
s: s};
}
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 3ace67a..84052c4 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -265,7 +265,7 @@
main() {
var f = /*info:INFERRED_TYPE_CLOSURE*/() sync* {
yield 1;
- yield* [3, 4.0];
+ yield* /*info:INFERRED_TYPE_LITERAL*/[3, 4.0];
};
Iterable<num> g = f();
Iterable<int> h = /*info:ASSIGNMENT_CAST*/f();
@@ -695,14 +695,16 @@
/*info:INFERRED_TYPE_LITERAL*/[3]]);
new F3(/*info:INFERRED_TYPE_LITERAL*/[]);
- new F3(/*info:INFERRED_TYPE_LITERAL*/[[3]]);
- new F3(/*info:INFERRED_TYPE_LITERAL*/[["hello"]]);
- new F3(/*info:INFERRED_TYPE_LITERAL*/[["hello"], [3]]);
+ new F3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+ new F3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/["hello"]]);
+ new F3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/["hello"],
+ /*info:INFERRED_TYPE_LITERAL*/[3]]);
new F4(a: /*info:INFERRED_TYPE_LITERAL*/[]);
- new F4(a: /*info:INFERRED_TYPE_LITERAL*/[[3]]);
- new F4(a: /*info:INFERRED_TYPE_LITERAL*/[["hello"]]);
- new F4(a: /*info:INFERRED_TYPE_LITERAL*/[["hello"], [3]]);
+ new F4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+ new F4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/["hello"]]);
+ new F4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/["hello"],
+ /*info:INFERRED_TYPE_LITERAL*/[3]]);
}
''');
}
@@ -884,9 +886,9 @@
}
{
List<dynamic> l0 = [];
- List<dynamic> l1 = [3];
- List<dynamic> l2 = ["hello"];
- List<dynamic> l3 = ["hello", 3];
+ List<dynamic> l1 = /*info:INFERRED_TYPE_LITERAL*/[3];
+ List<dynamic> l2 = /*info:INFERRED_TYPE_LITERAL*/["hello"];
+ List<dynamic> l3 = /*info:INFERRED_TYPE_LITERAL*/["hello", 3];
}
{
List<int> l0 = /*severe:STATIC_TYPE_ERROR*/<num>[];
@@ -997,10 +999,10 @@
}
{
Map<dynamic, dynamic> l0 = {};
- Map<dynamic, dynamic> l1 = {3: "hello"};
- Map<dynamic, dynamic> l2 = {"hello": "hello"};
- Map<dynamic, dynamic> l3 = {3: 3};
- Map<dynamic, dynamic> l4 = {3:"hello", "hello": 3};
+ Map<dynamic, dynamic> l1 = /*info:INFERRED_TYPE_LITERAL*/{3: "hello"};
+ Map<dynamic, dynamic> l2 = /*info:INFERRED_TYPE_LITERAL*/{"hello": "hello"};
+ Map<dynamic, dynamic> l3 = /*info:INFERRED_TYPE_LITERAL*/{3: 3};
+ Map<dynamic, dynamic> l4 = /*info:INFERRED_TYPE_LITERAL*/{3:"hello", "hello": 3};
}
{
Map<dynamic, String> l0 = /*info:INFERRED_TYPE_LITERAL*/{};
@@ -2372,17 +2374,80 @@
''');
}
+ void test_instanceField_basedOnInstanceField_betweenCycles() {
+ // Verify that all instance fields in one library cycle are inferred before
+ // an instance fields in a dependent library cycle.
+ addFile(
+ '''
+import 'b.dart';
+class A {
+ var x = new B().y;
+ var y = 0;
+}
+''',
+ name: '/a.dart');
+ addFile(
+ '''
+class B {
+ var x = new B().y;
+ var y = 0;
+}
+''',
+ name: '/b.dart');
+ checkFile('''
+import 'a.dart';
+import 'b.dart';
+main() {
+ new A().x = /*warning:INVALID_ASSIGNMENT*/'foo';
+ new B().x = 'foo';
+}
+''');
+ }
+
+ void test_instanceField_basedOnInstanceField_withinCycle() {
+ // Verify that all instance field inferences that occur within the same
+ // library cycle happen as though they occurred "all at once", so no
+ // instance field in the library cycle can inherit its type from another
+ // instance field in the same library cycle.
+ addFile(
+ '''
+import 'b.dart';
+class A {
+ var x = new B().y;
+ var y = 0;
+}
+''',
+ name: '/a.dart');
+ addFile(
+ '''
+import 'a.dart';
+class B {
+ var x = new A().y;
+ var y = 0;
+}
+''',
+ name: '/b.dart');
+ checkFile('''
+import 'a.dart';
+import 'b.dart';
+main() {
+ new A().x = 'foo';
+ new B().x = 'foo';
+}
+''');
+ }
+
void test_listLiterals() {
checkFile(r'''
test1() {
- var x = [1, 2, 3];
+ var x = /*info:INFERRED_TYPE_LITERAL*/[1, 2, 3];
x.add(/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi');
x.add(/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/4.0);
x.add(4);
List<num> y = x;
}
test2() {
- var x = [1, 2.0, 3];
+ var x = /*info:INFERRED_TYPE_LITERAL*/[1, 2.0, 3];
x.add(/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi');
x.add(4.0);
List<int> y = /*info:ASSIGNMENT_CAST*/x;
@@ -2392,14 +2457,14 @@
void test_listLiterals_topLevel() {
checkFile(r'''
-var x1 = [1, 2, 3];
+var x1 = /*info:INFERRED_TYPE_LITERAL*/[1, 2, 3];
test1() {
x1.add(/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi');
x1.add(/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/4.0);
x1.add(4);
List<num> y = x1;
}
-var x2 = [1, 2.0, 3];
+var x2 = /*info:INFERRED_TYPE_LITERAL*/[1, 2.0, 3];
test2() {
x2.add(/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi');
x2.add(4.0);
@@ -2422,7 +2487,7 @@
void test_mapLiterals() {
checkFile(r'''
test1() {
- var x = { 1: 'x', 2: 'y' };
+ var x = /*info:INFERRED_TYPE_LITERAL*/{ 1: 'x', 2: 'y' };
x[3] = 'z';
x[/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'] = 'w';
x[/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/4.0] = 'u';
@@ -2431,7 +2496,7 @@
}
test2() {
- var x = { 1: 'x', 2: 'y', 3.0: new RegExp('.') };
+ var x = /*info:INFERRED_TYPE_LITERAL*/{ 1: 'x', 2: 'y', 3.0: new RegExp('.') };
x[3] = 'z';
x[/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'] = 'w';
x[4.0] = 'u';
@@ -2445,7 +2510,7 @@
void test_mapLiterals_topLevel() {
checkFile(r'''
-var x1 = { 1: 'x', 2: 'y' };
+var x1 = /*info:INFERRED_TYPE_LITERAL*/{ 1: 'x', 2: 'y' };
test1() {
x1[3] = 'z';
x1[/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'] = 'w';
@@ -2454,7 +2519,7 @@
Map<num, String> y = x1;
}
-var x2 = { 1: 'x', 2: 'y', 3.0: new RegExp('.') };
+var x2 = /*info:INFERRED_TYPE_LITERAL*/{ 1: 'x', 2: 'y', 3.0: new RegExp('.') };
test2() {
x2[3] = 'z';
x2[/*warning:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'] = 'w';
diff --git a/pkg/analyzer/test/src/task/strong/test_all.dart b/pkg/analyzer/test/src/task/strong/test_all.dart
index be9a178..698e2ae 100644
--- a/pkg/analyzer/test/src/task/strong/test_all.dart
+++ b/pkg/analyzer/test/src/task/strong/test_all.dart
@@ -13,7 +13,7 @@
/// Utility for manually running all tests.
main() {
initializeTestEnvironment();
- group('task tests', () {
+ group('strong tests', () {
checker_test.main();
inferred_type_test.main();
});
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index c4589f7..3f4a5a6 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -7,7 +7,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/strong_mode.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/tool/summary/dump_inferred_types.dart b/pkg/analyzer/tool/summary/dump_inferred_types.dart
new file mode 100644
index 0000000..0668513
--- /dev/null
+++ b/pkg/analyzer/tool/summary/dump_inferred_types.dart
@@ -0,0 +1,275 @@
+// Copyright (c) 2016, 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:convert';
+import 'dart:io';
+
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/base.dart';
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Collect the inferred types from all the summary files listed in [args] and
+ * print them in alphabetical order.
+ */
+main(List<String> args) {
+ InferredTypeCollector collector = new InferredTypeCollector();
+ for (String arg in args) {
+ PackageBundle bundle =
+ new PackageBundle.fromBuffer(new File(arg).readAsBytesSync());
+ collector.visitPackageBundle(bundle);
+ }
+ collector.dumpCollectedTypes();
+}
+
+/**
+ * Visitor class that visits the contents of a summary file and collects the
+ * inferred types in it.
+ */
+class InferredTypeCollector {
+ UnlinkedUnit unlinkedUnit;
+ LinkedUnit linkedUnit;
+ final Map<String, String> inferredTypes = <String, String>{};
+ List<String> typeParamsInScope = <String>[];
+
+ /**
+ * If an inferred type exists matching the given [slot], record that it is the
+ * type of the entity reachable via [path].
+ */
+ void collectInferredType(int slot, String path) {
+ for (EntityRef type in linkedUnit.types) {
+ if (type.slot == slot) {
+ inferredTypes[path] = formatType(type);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Collect the inferred type in summary object [obj] (if any), which is
+ * reachable via [path].
+ *
+ * This method may modify [properties] in order to affect how sub-elements
+ * are visited.
+ */
+ void collectInferredTypes(
+ SummaryClass obj, Map<String, Object> properties, String path) {
+ if (obj is UnlinkedVariable) {
+ collectInferredType(obj.inferredTypeSlot, path);
+ } else if (obj is UnlinkedExecutable) {
+ collectInferredType(obj.inferredReturnTypeSlot, path);
+ } else if (obj is UnlinkedParam) {
+ collectInferredType(obj.inferredTypeSlot, path);
+ // As a temporary measure, prevent recursion into the parameter's
+ // initializer, since AST-based type inference doesn't infer its type
+ // correctly yet. TODO(paulberry): fix.
+ properties.remove('initializer');
+ }
+ }
+
+ /**
+ * Print out all the inferred types collected so far, in alphabetical order.
+ */
+ void dumpCollectedTypes() {
+ List<String> paths = inferredTypes.keys.toList();
+ paths.sort();
+ for (String path in paths) {
+ print('$path -> ${inferredTypes[path]}');
+ }
+ }
+
+ /**
+ * Interpret the given [param] as a parameter in a synthetic typedef, and
+ * format it as a string.
+ */
+ String formatParam(UnlinkedParam param) {
+ if (param.isFunctionTyped) {
+ // TODO(paulberry): fix this case.
+ return 'BAD(${JSON.encode(param)})';
+ }
+ String result;
+ if (param.type != null) {
+ result = '${formatType(param.type)} ${param.name}';
+ } else {
+ result = param.name;
+ }
+ if (param.kind == UnlinkedParamKind.named) {
+ result = '{$result}';
+ } else if (param.kind == UnlinkedParamKind.positional) {
+ result = '[$result]';
+ }
+ return result;
+ }
+
+ /**
+ * Convert the reference with index [index] into a string. If [typeOf] is
+ * `true`, the reference is being used in the context of naming a type, so
+ * if the entity being referenced is not a type, it will be enclosed in
+ * `typeof()` for clarity.
+ */
+ String formatReference(int index, {bool typeOf: false}) {
+ LinkedReference linkedRef = linkedUnit.references[index];
+ switch (linkedRef.kind) {
+ case ReferenceKind.classOrEnum:
+ case ReferenceKind.function:
+ case ReferenceKind.propertyAccessor:
+ case ReferenceKind.topLevelFunction:
+ case ReferenceKind.method:
+ case ReferenceKind.typedef:
+ case ReferenceKind.prefix:
+ case ReferenceKind.topLevelPropertyAccessor:
+ break;
+ default:
+ // TODO(paulberry): fix this case.
+ return 'BAD(${JSON.encode(linkedRef.toJson())})';
+ }
+ int containingReference;
+ String name;
+ if (index < unlinkedUnit.references.length) {
+ containingReference = unlinkedUnit.references[index].prefixReference;
+ name = unlinkedUnit.references[index].name;
+ } else {
+ containingReference = linkedRef.containingReference;
+ name = linkedRef.name;
+ }
+ String result;
+ if (containingReference != 0) {
+ result = '${formatReference(containingReference)}.$name';
+ } else {
+ result = name;
+ }
+ if (linkedRef.kind == ReferenceKind.function) {
+ assert(name.isEmpty);
+ result += 'localFunction[${linkedRef.localIndex}]';
+ }
+ if (!typeOf ||
+ linkedRef.kind == ReferenceKind.classOrEnum ||
+ linkedRef.kind == ReferenceKind.typedef) {
+ return result;
+ } else {
+ return 'typeof($result)';
+ }
+ }
+
+ /**
+ * Interpret the given [entityRef] as a reference to a type, and format it as
+ * a string.
+ */
+ String formatType(EntityRef entityRef) {
+ List<int> implicitFunctionTypeIndices =
+ entityRef.implicitFunctionTypeIndices;
+ if (entityRef.syntheticReturnType != null) {
+ String params = entityRef.syntheticParams.map(formatParam).join(', ');
+ String retType = formatType(entityRef.syntheticReturnType);
+ return '($params) -> $retType';
+ }
+ if (entityRef.paramReference != 0) {
+ return typeParamsInScope[
+ typeParamsInScope.length - entityRef.paramReference];
+ }
+ String result = formatReference(entityRef.reference, typeOf: true);
+ if (entityRef.typeArguments.isNotEmpty) {
+ result += '<${entityRef.typeArguments.map(formatType).join(', ')}>';
+ }
+ if (implicitFunctionTypeIndices.isNotEmpty) {
+ result =
+ 'parameterOf($result, ${implicitFunctionTypeIndices.join(', ')})';
+ }
+ return result;
+ }
+
+ /**
+ * Collect all the inferred types contained in [obj], which is reachable via
+ * [path]. [properties] is the result of calling `obj.toMap()`, and may be
+ * modified before returning.
+ */
+ void visit(SummaryClass obj, Map<String, Object> properties, String path) {
+ List<String> oldTypeParamsInScope = typeParamsInScope;
+ Object newTypeParams = properties['typeParameters'];
+ if (newTypeParams is List && newTypeParams.isNotEmpty) {
+ typeParamsInScope = typeParamsInScope.toList();
+ for (Object typeParam in newTypeParams) {
+ if (typeParam is UnlinkedTypeParam) {
+ typeParamsInScope.add(typeParam.name);
+ } else {
+ throw new StateError(
+ 'Unexpected type param type: ${typeParam.runtimeType}');
+ }
+ }
+ }
+ collectInferredTypes(obj, properties, path);
+ properties.forEach((String key, Object value) {
+ if (value is SummaryClass) {
+ visit(value, value.toMap(), '$path.$key');
+ } else if (value is List) {
+ for (int i = 0; i < value.length; i++) {
+ Object item = value[i];
+ if (item is SummaryClass) {
+ Map<String, Object> itemProperties = item.toMap();
+ String indexOrName = itemProperties['name'] ?? i.toString();
+ visit(item, itemProperties, '$path.$key[$indexOrName]');
+ }
+ }
+ }
+ });
+ typeParamsInScope = oldTypeParamsInScope;
+ }
+
+ /**
+ * Collect all the inferred types contained in [bundle].
+ */
+ void visitPackageBundle(PackageBundle bundle) {
+ Map<String, LinkedLibrary> linkedLibraries = <String, LinkedLibrary>{};
+ Map<String, UnlinkedUnit> unlinkedUnits = <String, UnlinkedUnit>{};
+ for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
+ linkedLibraries[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
+ }
+ for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
+ unlinkedUnits[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
+ }
+ // Figure out which unlinked units are a part of another library so we won't
+ // visit them redundantly.
+ Set<String> partOfUris = new Set<String>();
+ unlinkedUnits.forEach((String unitUriString, UnlinkedUnit unlinkedUnit) {
+ Uri unitUri = Uri.parse(unitUriString);
+ for (String relativePartUriString in unlinkedUnit.publicNamespace.parts) {
+ partOfUris.add(
+ resolveRelativeUri(unitUri, Uri.parse(relativePartUriString))
+ .toString());
+ }
+ });
+ linkedLibraries
+ .forEach((String libraryUriString, LinkedLibrary linkedLibrary) {
+ if (partOfUris.contains(libraryUriString)) {
+ return;
+ }
+ Uri libraryUri = Uri.parse(libraryUriString);
+ UnlinkedUnit definingUnlinkedUnit = unlinkedUnits[libraryUriString];
+ visitUnit(definingUnlinkedUnit, linkedLibrary.units[0], libraryUriString);
+ for (int i = 0;
+ i < definingUnlinkedUnit.publicNamespace.parts.length;
+ i++) {
+ Uri relativePartUri =
+ Uri.parse(definingUnlinkedUnit.publicNamespace.parts[i]);
+ String unitUriString =
+ resolveRelativeUri(libraryUri, relativePartUri).toString();
+ visitUnit(unlinkedUnits[unitUriString], linkedLibrary.units[i + 1],
+ libraryUriString);
+ }
+ });
+ }
+
+ /**
+ * Collect all the inferred types contained in the compilation unit described
+ * by [unlinkedUnit] and [linkedUnit], which has URI [libraryUriString].
+ */
+ void visitUnit(UnlinkedUnit unlinkedUnit, LinkedUnit linkedUnit,
+ String libraryUriString) {
+ this.unlinkedUnit = unlinkedUnit;
+ this.linkedUnit = linkedUnit;
+ visit(unlinkedUnit, unlinkedUnit.toMap(), libraryUriString);
+ this.unlinkedUnit = null;
+ this.linkedUnit = null;
+ }
+}
diff --git a/pkg/analyzer/tool/summary/inspect.dart b/pkg/analyzer/tool/summary/inspect.dart
new file mode 100644
index 0000000..eb0093d
--- /dev/null
+++ b/pkg/analyzer/tool/summary/inspect.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/inspect.dart';
+import 'package:args/args.dart';
+
+main(List<String> args) {
+ ArgParser argParser = new ArgParser()..addFlag('raw');
+ ArgResults argResults = argParser.parse(args);
+ if (argResults.rest.length != 1) {
+ print(argParser.usage);
+ exitCode = 1;
+ return;
+ }
+ String path = argResults.rest[0];
+ List<int> bytes = new File(path).readAsBytesSync();
+ PackageBundle bundle = new PackageBundle.fromBuffer(bytes);
+ SummaryInspector inspector = new SummaryInspector(argResults['raw']);
+ print(inspector.dumpPackageBundle(bundle).join('\n'));
+}
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 4142a2a..75e8989 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -172,7 +172,10 @@
LINTS [shape=box]
LibraryErrorsReadyTask -> LIBRARY_ERRORS_READY
LibraryUnitErrorsTask -> LIBRARY_UNIT_ERRORS
+ MODIFICATION_TIME -> BuildDirectiveElementsTask
MODIFICATION_TIME -> ParseDartTask
+ MODIFICATION_TIME -> ScanDartTask
+ MODIFICATION_TIME -> VerifyUnitTask
MODIFICATION_TIME [shape=box]
PARSED_UNIT -> BuildCompilationUnitElementTask
PARSED_UNIT -> DartErrorsTask
@@ -193,6 +196,7 @@
ParseDartTask -> LIBRARY_SPECIFIC_UNITS
ParseDartTask -> PARSED_UNIT
ParseDartTask -> PARSE_ERRORS
+ ParseDartTask -> REFERENCED_SOURCES
ParseDartTask -> SOURCE_KIND
ParseDartTask -> UNITS
PartiallyResolveUnitReferencesTask -> CREATED_RESOLVED_UNIT6
@@ -217,6 +221,9 @@
READY_RESOLVED_UNIT -> VerifyUnitTask
READY_RESOLVED_UNIT [shape=box]
REFERENCED_NAMES [shape=box]
+ REFERENCED_SOURCES -> BuildDirectiveElementsTask
+ REFERENCED_SOURCES -> VerifyUnitTask
+ REFERENCED_SOURCES [shape=box]
RESOLVED_UNIT -> GenerateHintsTask
RESOLVED_UNIT -> GenerateLintsTask
RESOLVED_UNIT -> ReadyResolvedUnitTask
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index 7314a20..b3e9398 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -20,6 +20,7 @@
import 'package:analyzer_cli/src/driver.dart';
import 'package:analyzer_cli/src/error_formatter.dart';
import 'package:analyzer_cli/src/options.dart';
+import 'package:path/path.dart' as pathos;
/// The maximum number of sources for which AST structures should be kept in the cache.
const int _maxCacheSize = 512;
@@ -179,11 +180,15 @@
/// Returns true if we want to report diagnostics for this library.
bool _isAnalyzedLibrary(LibraryElement library) {
- switch (library.source.uriKind) {
+ Source source = library.source;
+ switch (source.uriKind) {
case UriKind.DART_URI:
return options.showSdkWarnings;
case UriKind.PACKAGE_URI:
- return _isAnalyzedPackage(library.source.uri);
+ if (_isPathInPubCache(source.fullName)) {
+ return false;
+ }
+ return _isAnalyzedPackage(source.uri);
default:
return true;
}
@@ -194,7 +199,6 @@
if (uri.scheme != 'package' || uri.pathSegments.isEmpty) {
return false;
}
-
String packageName = uri.pathSegments.first;
if (packageName == _selfPackageName) {
return true;
@@ -328,6 +332,20 @@
return new ProcessedSeverity(severity, isOverridden);
}
+
+ /// Return `true` if the given [path] is in the Pub cache.
+ static bool _isPathInPubCache(String path) {
+ List<String> parts = pathos.split(path);
+ if (parts.contains('.pub-cache')) {
+ return true;
+ }
+ for (int i = 0; i < parts.length - 2; i++) {
+ if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') {
+ return true;
+ }
+ }
+ return false;
+ }
}
/// This [Logger] prints out information comments to [outSink] and error messages
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index 511c6c0..e60ec09 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -28,10 +28,93 @@
import 'package:analyzer_cli/src/driver.dart';
import 'package:analyzer_cli/src/error_formatter.dart';
import 'package:analyzer_cli/src/options.dart';
-import 'package:protobuf/protobuf.dart';
+import 'package:bazel_worker/bazel_worker.dart';
-import 'message_grouper.dart';
-import 'worker_protocol.pb.dart';
+/**
+ * Persistent Bazel worker.
+ */
+class AnalyzerWorkerLoop extends SyncWorkerLoop {
+ final StringBuffer errorBuffer = new StringBuffer();
+ final StringBuffer outBuffer = new StringBuffer();
+
+ final String dartSdkPath;
+
+ AnalyzerWorkerLoop(SyncWorkerConnection connection, {this.dartSdkPath})
+ : super(connection: connection);
+
+ factory AnalyzerWorkerLoop.std(
+ {io.Stdin stdinStream, io.Stdout stdoutStream, String dartSdkPath}) {
+ SyncWorkerConnection connection = new StdSyncWorkerConnection(
+ stdinStream: stdinStream, stdoutStream: stdoutStream);
+ return new AnalyzerWorkerLoop(connection, dartSdkPath: dartSdkPath);
+ }
+
+ /**
+ * Performs analysis with given [options].
+ */
+ void analyze(CommandLineOptions options) {
+ new BuildMode(options, new AnalysisStats()).analyze();
+ AnalysisEngine.instance.clearCaches();
+ }
+
+ /**
+ * Perform a single loop step.
+ */
+ WorkResponse performRequest(WorkRequest request) {
+ errorBuffer.clear();
+ outBuffer.clear();
+ try {
+ // Add in the dart-sdk argument if `dartSdkPath` is not null, otherwise it
+ // will try to find the currently installed sdk.
+ var arguments = new List.from(request.arguments);
+ if (dartSdkPath != null &&
+ !arguments.any((arg) => arg.startsWith('--dart-sdk'))) {
+ arguments.add('--dart-sdk=$dartSdkPath');
+ }
+ // Prepare options.
+ CommandLineOptions options =
+ CommandLineOptions.parse(arguments, (String msg) {
+ throw new ArgumentError(msg);
+ });
+ // Analyze and respond.
+ analyze(options);
+ String msg = _getErrorOutputBuffersText();
+ return new WorkResponse()
+ ..exitCode = EXIT_CODE_OK
+ ..output = msg;
+ } catch (e, st) {
+ String msg = _getErrorOutputBuffersText();
+ msg += '$e\n$st';
+ return new WorkResponse()
+ ..exitCode = EXIT_CODE_ERROR
+ ..output = msg;
+ }
+ }
+
+ /**
+ * Run the worker loop.
+ */
+ @override
+ void run() {
+ errorSink = errorBuffer;
+ outSink = outBuffer;
+ exitHandler = (int exitCode) {
+ return throw new StateError('Exit called: $exitCode');
+ };
+ super.run();
+ }
+
+ String _getErrorOutputBuffersText() {
+ String msg = '';
+ if (errorBuffer.isNotEmpty) {
+ msg += errorBuffer.toString() + '\n';
+ }
+ if (outBuffer.isNotEmpty) {
+ msg += outBuffer.toString() + '\n';
+ }
+ return msg;
+ }
+}
/**
* Analyzer used when the "--build-mode" option is supplied.
@@ -46,7 +129,7 @@
Map<Uri, JavaFile> uriToFileMap;
final List<Source> explicitSources = <Source>[];
- PackageBundleAssembler assembler = new PackageBundleAssembler();
+ PackageBundleAssembler assembler;
final Set<Source> processedSources = new Set<Source>();
final Map<Uri, UnlinkedUnit> uriToUnit = <Uri, UnlinkedUnit>{};
@@ -97,6 +180,8 @@
}
// Write summary.
+ assembler = new PackageBundleAssembler(
+ excludeHashes: options.buildSummaryExcludeInformative);
if (options.buildSummaryOutput != null) {
if (options.buildSummaryOnlyAst && !options.buildSummaryFallback) {
_serializeAstBasedSummary(explicitSources);
@@ -120,7 +205,6 @@
PackageBundleBuilder sdkBundle = assembler.assemble();
if (options.buildSummaryExcludeInformative) {
sdkBundle.flushInformative();
- sdkBundle.unlinkedUnitHashes = null;
}
io.File file = new io.File(options.buildSummaryOutput);
file.writeAsBytesSync(sdkBundle.toBuffer(), mode: io.FileMode.WRITE_ONLY);
@@ -157,7 +241,7 @@
new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
sdk.analysisOptions =
Driver.createAnalysisOptionsForCommandLineOptions(options);
- sdk.useSummary = true;
+ sdk.useSummary = !options.buildSummaryOnlyAst;
// Read the summaries.
summaryDataStore = new SummaryDataStore(options.buildSummaryInputs);
@@ -183,10 +267,12 @@
}
});
- // Configure using summaries.
- context.typeProvider = sdk.context.typeProvider;
- context.resultProvider =
- new InputPackagesResultProvider(context, summaryDataStore);
+ if (!options.buildSummaryOnlyAst) {
+ // Configure using summaries.
+ context.typeProvider = sdk.context.typeProvider;
+ context.resultProvider =
+ new InputPackagesResultProvider(context, summaryDataStore);
+ }
}
/**
@@ -273,142 +359,3 @@
return uriToFileMap;
}
}
-
-/**
- * Default implementation of [WorkerConnection] that works with stdio.
- */
-class StdWorkerConnection implements WorkerConnection {
- final MessageGrouper _messageGrouper;
- final io.Stdout _stdoutStream;
-
- StdWorkerConnection(io.Stdin stdinStream, this._stdoutStream)
- : _messageGrouper = new MessageGrouper(stdinStream);
-
- @override
- WorkRequest readRequest() {
- var buffer = _messageGrouper.next;
- if (buffer == null) return null;
-
- return new WorkRequest.fromBuffer(buffer);
- }
-
- @override
- void writeResponse(WorkResponse response) {
- var responseBuffer = response.writeToBuffer();
-
- var writer = new CodedBufferWriter();
- writer.writeInt32NoTag(responseBuffer.length);
- writer.writeRawBytes(responseBuffer);
-
- _stdoutStream.add(writer.toBuffer());
- }
-}
-
-/**
- * Connection between a worker and input / output.
- */
-abstract class WorkerConnection {
- /**
- * Read a new [WorkRequest]. Returns [null] when there are no more requests.
- */
- WorkRequest readRequest();
-
- /**
- * Write the given [response] as bytes to the output.
- */
- void writeResponse(WorkResponse response);
-}
-
-/**
- * Persistent Bazel worker.
- */
-class WorkerLoop {
- static const int EXIT_CODE_OK = 0;
- static const int EXIT_CODE_ERROR = 15;
-
- final WorkerConnection connection;
-
- final StringBuffer errorBuffer = new StringBuffer();
- final StringBuffer outBuffer = new StringBuffer();
-
- final String dartSdkPath;
-
- WorkerLoop(this.connection, {this.dartSdkPath});
-
- factory WorkerLoop.std(
- {io.Stdin stdinStream, io.Stdout stdoutStream, String dartSdkPath}) {
- stdinStream ??= io.stdin;
- stdoutStream ??= io.stdout;
- WorkerConnection connection =
- new StdWorkerConnection(stdinStream, stdoutStream);
- return new WorkerLoop(connection, dartSdkPath: dartSdkPath);
- }
-
- /**
- * Performs analysis with given [options].
- */
- void analyze(CommandLineOptions options) {
- options.dartSdkPath ??= dartSdkPath;
- new BuildMode(options, new AnalysisStats()).analyze();
- }
-
- /**
- * Perform a single loop step. Return `true` if should exit the loop.
- */
- bool performSingle() {
- try {
- WorkRequest request = connection.readRequest();
- if (request == null) {
- return true;
- }
- // Prepare options.
- CommandLineOptions options =
- CommandLineOptions.parse(request.arguments, (String msg) {
- throw new ArgumentError(msg);
- });
- // Analyze and respond.
- analyze(options);
- String msg = _getErrorOutputBuffersText();
- connection.writeResponse(new WorkResponse()
- ..exitCode = EXIT_CODE_OK
- ..output = msg);
- } catch (e, st) {
- String msg = _getErrorOutputBuffersText();
- msg += '$e \n $st';
- connection.writeResponse(new WorkResponse()
- ..exitCode = EXIT_CODE_ERROR
- ..output = msg);
- }
- return false;
- }
-
- /**
- * Run the worker loop.
- */
- void run() {
- errorSink = errorBuffer;
- outSink = outBuffer;
- exitHandler = (int exitCode) {
- return throw new StateError('Exit called: $exitCode');
- };
- while (true) {
- errorBuffer.clear();
- outBuffer.clear();
- bool shouldExit = performSingle();
- if (shouldExit) {
- break;
- }
- }
- }
-
- String _getErrorOutputBuffersText() {
- String msg = '';
- if (errorBuffer.isNotEmpty) {
- msg += errorBuffer.toString() + '\n';
- }
- if (outBuffer.isNotEmpty) {
- msg += outBuffer.toString() + '\n';
- }
- return msg;
- }
-}
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index a05f81e..6a67547 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -245,7 +245,7 @@
ErrorSeverity _buildModeAnalyze(CommandLineOptions options) {
return _analyzeAllTag.makeCurrentWhile(() {
if (options.buildModePersistentWorker) {
- new WorkerLoop.std(dartSdkPath: options.dartSdkPath).run();
+ new AnalyzerWorkerLoop.std(dartSdkPath: options.dartSdkPath).run();
} else {
return new BuildMode(options, stats).analyze();
}
@@ -298,10 +298,6 @@
if (options.enableSuperMixins != _previousOptions.enableSuperMixins) {
return false;
}
- if (options.enableConditionalDirectives !=
- _previousOptions.enableConditionalDirectives) {
- return false;
- }
return true;
}
@@ -603,8 +599,6 @@
contextOptions.hint = !options.disableHints;
contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
contextOptions.enableSuperMixins = options.enableSuperMixins;
- contextOptions.enableConditionalDirectives =
- options.enableConditionalDirectives;
contextOptions.generateImplicitErrors = options.showPackageWarnings;
contextOptions.generateSdkErrors = options.showSdkWarnings;
contextOptions.lint = options.lints;
diff --git a/pkg/analyzer_cli/lib/src/message_grouper.dart b/pkg/analyzer_cli/lib/src/message_grouper.dart
deleted file mode 100644
index 8696796..0000000
--- a/pkg/analyzer_cli/lib/src/message_grouper.dart
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:io';
-import 'dart:typed_data';
-
-/// Groups stdin input into messages by interpreting it as
-/// base-128 encoded lengths interleaved with raw data.
-///
-/// The base-128 encoding is in little-endian order, with the high bit set on
-/// all bytes but the last. This was chosen since it's the same as the
-/// base-128 encoding used by protobufs, so it allows a modest amount of code
-/// reuse at the other end of the protocol.
-///
-/// Possible future improvements to consider (should a debugging need arise):
-/// - Put a magic number at the beginning of the stream.
-/// - Use a guard byte between messages to sanity check that the encoder and
-/// decoder agree on the encoding of lengths.
-class MessageGrouper {
- final _state = new _MessageGrouperState();
- final Stdin _stdin;
-
- MessageGrouper(this._stdin);
-
- /// Blocks until the next full message is received, and then returns it.
- ///
- /// Returns null at end of file.
- List<int> get next {
- var message;
- while (message == null) {
- var nextByte = _stdin.readByteSync();
- if (nextByte == -1) return null;
- message = _state.handleInput(nextByte);
- }
- return message;
- }
-}
-
-/// State held by the [MessageGrouper] while waiting for additional data to
-/// arrive.
-class _MessageGrouperState {
- /// `true` means we are waiting to receive bytes of base-128 encoded length.
- /// Some bytes of length may have been received already.
- ///
- /// `false` means we are waiting to receive more bytes of message data. Some
- /// bytes of message data may have been received already.
- bool waitingForLength = true;
-
- /// If [waitingForLength] is `true`, the decoded value of the length bytes
- /// received so far (if any). If [waitingForLength] is `false`, the decoded
- /// length that was most recently received.
- int length = 0;
-
- /// If [waitingForLength] is `true`, the amount by which the next received
- /// length byte must be left-shifted; otherwise undefined.
- int lengthShift = 0;
-
- /// If [waitingForLength] is `false`, a [Uint8List] which is ready to receive
- /// message data. Otherwise null.
- Uint8List message;
-
- /// If [waitingForLength] is `false`, the number of message bytes that have
- /// been received so far. Otherwise zero.
- int numMessageBytesReceived;
-
- _MessageGrouperState() {
- reset();
- }
-
- /// Handle one byte at a time.
- ///
- /// Returns a [List<int>] of message bytes if [byte] was the last byte in a
- /// message, otherwise returns [null].
- List<int> handleInput(int byte) {
- if (waitingForLength) {
- length |= (byte & 0x7f) << lengthShift;
- if ((byte & 0x80) == 0) {
- waitingForLength = false;
- message = new Uint8List(length);
- if (length == 0) {
- // There is no message data to wait for, so just go ahead and deliver the
- // empty message.
- var messageToReturn = message;
- reset();
- return messageToReturn;
- }
- } else {
- lengthShift += 7;
- }
- } else {
- message[numMessageBytesReceived] = byte;
- numMessageBytesReceived++;
- if (numMessageBytesReceived == length) {
- var messageToReturn = message;
- reset();
- return messageToReturn;
- }
- }
- return null;
- }
-
- /// Reset the state so that we are ready to receive the next base-128 encoded
- /// length.
- void reset() {
- waitingForLength = true;
- length = 0;
- lengthShift = 0;
- message = null;
- numMessageBytesReceived = 0;
- }
-}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index fc778f4..3f26109 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -80,9 +80,6 @@
/// Whether to display version information
final bool displayVersion;
- /// Whether to enable conditional directives (DEP 40).
- final bool enableConditionalDirectives;
-
/// Whether to enable null-aware operators (DEP 9).
final bool enableNullAwareOperators;
@@ -166,7 +163,6 @@
analysisOptionsFile = args['options'],
disableHints = args['no-hints'],
displayVersion = args['version'],
- enableConditionalDirectives = args['enable-conditional-directives'],
enableNullAwareOperators = args['enable-null-aware-operators'],
enableStrictCallChecks = args['enable-strict-call-checks'],
enableSuperMixins = args['supermixin'],
@@ -419,7 +415,8 @@
negatable: false,
hide: true)
..addFlag('enable-conditional-directives',
- help: 'Enable support for conditional directives (DEP 40).',
+ help:
+ 'deprecated -- Enable support for conditional directives (DEP 40).',
defaultsTo: false,
negatable: false,
hide: true)
@@ -434,7 +431,7 @@
negatable: false,
hide: true)
..addFlag('enable-new-task-model',
- help: 'Ennable new task model.',
+ help: 'deprecated -- Ennable new task model.',
defaultsTo: false,
negatable: false,
hide: true)
diff --git a/pkg/analyzer_cli/lib/src/perf_report.dart b/pkg/analyzer_cli/lib/src/perf_report.dart
index f92ae9a..452b2ff 100644
--- a/pkg/analyzer_cli/lib/src/perf_report.dart
+++ b/pkg/analyzer_cli/lib/src/perf_report.dart
@@ -5,7 +5,7 @@
library analyzer_cli.src.perf_report;
import 'dart:convert' show JsonEncoder;
-import 'dart:io' show File, Platform;
+import 'dart:io' show Platform;
import 'package:analyzer/src/generated/utilities_general.dart'
show PerformanceTag;
diff --git a/pkg/analyzer_cli/lib/src/worker_protocol.pb.dart b/pkg/analyzer_cli/lib/src/worker_protocol.pb.dart
deleted file mode 100755
index 908dfac..0000000
--- a/pkg/analyzer_cli/lib/src/worker_protocol.pb.dart
+++ /dev/null
@@ -1,133 +0,0 @@
-///
-// Generated code. Do not modify.
-///
-library blaze.worker_worker_protocol;
-
-import 'package:protobuf/protobuf.dart';
-
-class Input extends GeneratedMessage {
- static final BuilderInfo _i = new BuilderInfo('Input')
- ..a(1, 'path', PbFieldType.OS)
- ..a(2, 'digest', PbFieldType.OY)
- ..hasRequiredFields = false
- ;
-
- Input() : super();
- Input.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
- Input.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
- Input clone() => new Input()..mergeFromMessage(this);
- BuilderInfo get info_ => _i;
- static Input create() => new Input();
- static PbList<Input> createRepeated() => new PbList<Input>();
- static Input getDefault() {
- if (_defaultInstance == null) _defaultInstance = new _ReadonlyInput();
- return _defaultInstance;
- }
- static Input _defaultInstance;
- static void $checkItem(Input v) {
- if (v is !Input) checkItemFailed(v, 'Input');
- }
-
- String get path => $_get(0, 1, '');
- void set path(String v) { $_setString(0, 1, v); }
- bool hasPath() => $_has(0, 1);
- void clearPath() => clearField(1);
-
- List<int> get digest => $_get(1, 2, null);
- void set digest(List<int> v) { $_setBytes(1, 2, v); }
- bool hasDigest() => $_has(1, 2);
- void clearDigest() => clearField(2);
-}
-
-class _ReadonlyInput extends Input with ReadonlyMessageMixin {}
-
-class WorkRequest extends GeneratedMessage {
- static final BuilderInfo _i = new BuilderInfo('WorkRequest')
- ..p(1, 'arguments', PbFieldType.PS)
- ..pp(2, 'inputs', PbFieldType.PM, Input.$checkItem, Input.create)
- ..hasRequiredFields = false
- ;
-
- WorkRequest() : super();
- WorkRequest.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
- WorkRequest.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
- WorkRequest clone() => new WorkRequest()..mergeFromMessage(this);
- BuilderInfo get info_ => _i;
- static WorkRequest create() => new WorkRequest();
- static PbList<WorkRequest> createRepeated() => new PbList<WorkRequest>();
- static WorkRequest getDefault() {
- if (_defaultInstance == null) _defaultInstance = new _ReadonlyWorkRequest();
- return _defaultInstance;
- }
- static WorkRequest _defaultInstance;
- static void $checkItem(WorkRequest v) {
- if (v is !WorkRequest) checkItemFailed(v, 'WorkRequest');
- }
-
- List<String> get arguments => $_get(0, 1, null);
-
- List<Input> get inputs => $_get(1, 2, null);
-}
-
-class _ReadonlyWorkRequest extends WorkRequest with ReadonlyMessageMixin {}
-
-class WorkResponse extends GeneratedMessage {
- static final BuilderInfo _i = new BuilderInfo('WorkResponse')
- ..a(1, 'exitCode', PbFieldType.O3)
- ..a(2, 'output', PbFieldType.OS)
- ..hasRequiredFields = false
- ;
-
- WorkResponse() : super();
- WorkResponse.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
- WorkResponse.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
- WorkResponse clone() => new WorkResponse()..mergeFromMessage(this);
- BuilderInfo get info_ => _i;
- static WorkResponse create() => new WorkResponse();
- static PbList<WorkResponse> createRepeated() => new PbList<WorkResponse>();
- static WorkResponse getDefault() {
- if (_defaultInstance == null) _defaultInstance = new _ReadonlyWorkResponse();
- return _defaultInstance;
- }
- static WorkResponse _defaultInstance;
- static void $checkItem(WorkResponse v) {
- if (v is !WorkResponse) checkItemFailed(v, 'WorkResponse');
- }
-
- int get exitCode => $_get(0, 1, 0);
- void set exitCode(int v) { $_setUnsignedInt32(0, 1, v); }
- bool hasExitCode() => $_has(0, 1);
- void clearExitCode() => clearField(1);
-
- String get output => $_get(1, 2, '');
- void set output(String v) { $_setString(1, 2, v); }
- bool hasOutput() => $_has(1, 2);
- void clearOutput() => clearField(2);
-}
-
-class _ReadonlyWorkResponse extends WorkResponse with ReadonlyMessageMixin {}
-
-const Input$json = const {
- '1': 'Input',
- '2': const [
- const {'1': 'path', '3': 1, '4': 1, '5': 9},
- const {'1': 'digest', '3': 2, '4': 1, '5': 12},
- ],
-};
-
-const WorkRequest$json = const {
- '1': 'WorkRequest',
- '2': const [
- const {'1': 'arguments', '3': 1, '4': 3, '5': 9},
- const {'1': 'inputs', '3': 2, '4': 3, '5': 11, '6': '.blaze.worker.Input'},
- ],
-};
-
-const WorkResponse$json = const {
- '1': 'WorkResponse',
- '2': const [
- const {'1': 'exit_code', '3': 1, '4': 1, '5': 5},
- const {'1': 'output', '3': 2, '4': 1, '5': 9},
- ],
-};
-
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
index a1b2fe8..dbccd97 100644
--- a/pkg/analyzer_cli/pubspec.yaml
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -8,6 +8,7 @@
dependencies:
analyzer: ^0.27.0
args: ^0.13.0
+ bazel_worker: ^0.1.0
cli_util: ^0.0.1
linter: ^0.1.10
package_config: ^0.1.1
diff --git a/pkg/analyzer_cli/test/all.dart b/pkg/analyzer_cli/test/all.dart
index 05d8a98..13f72d1 100644
--- a/pkg/analyzer_cli/test/all.dart
+++ b/pkg/analyzer_cli/test/all.dart
@@ -6,7 +6,6 @@
import 'build_mode_test.dart' as build_mode_test;
import 'driver_test.dart' as driver;
import 'error_test.dart' as error;
-import 'message_grouper_test.dart' as message_grouper;
import 'options_test.dart' as options;
import 'package_prefix_test.dart' as package_prefix;
import 'perf_report_test.dart' as perf;
@@ -25,7 +24,6 @@
//sdk_ext.main();
//strong_mode.main();
error.main();
- message_grouper.main();
options.main();
perf.main();
plugin_manager.main();
diff --git a/pkg/analyzer_cli/test/build_mode_test.dart b/pkg/analyzer_cli/test/build_mode_test.dart
index dcc2423..9c88a0f 100644
--- a/pkg/analyzer_cli/test/build_mode_test.dart
+++ b/pkg/analyzer_cli/test/build_mode_test.dart
@@ -4,35 +4,28 @@
library analyzer_cli.test.built_mode;
-import 'dart:collection';
-import 'dart:convert';
-import 'dart:io';
-
import 'package:analyzer_cli/src/build_mode.dart';
import 'package:analyzer_cli/src/driver.dart';
import 'package:analyzer_cli/src/options.dart';
-import 'package:analyzer_cli/src/worker_protocol.pb.dart';
+import 'package:bazel_worker/bazel_worker.dart';
+import 'package:bazel_worker/testing.dart';
import 'package:protobuf/protobuf.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
-import 'utils.dart';
-
main() {
defineReflectiveTests(WorkerLoopTest);
}
-typedef void _TestWorkerLoopAnalyze(CommandLineOptions options);
-
@reflectiveTest
class WorkerLoopTest {
- final TestStdinStream stdinStream = new TestStdinStream();
+ final TestStdinSync stdinStream = new TestStdinSync();
final TestStdoutStream stdoutStream = new TestStdoutStream();
- _TestWorkerConnection connection;
+ TestSyncWorkerConnection connection;
WorkerLoopTest() {
- connection = new _TestWorkerConnection(this.stdinStream, this.stdoutStream);
+ connection =
+ new TestSyncWorkerConnection(this.stdinStream, this.stdoutStream);
}
void setUp() {}
@@ -56,8 +49,9 @@
'package:foo/bar.dart|/inputs/foo/lib/bar.dart',
]);
stdinStream.addInputBytes(_serializeProto(request));
+ stdinStream.close();
- new _TestWorkerLoop(connection, (CommandLineOptions options) {
+ new TestAnalyzerWorkerLoop(connection, (CommandLineOptions options) {
expect(options.buildSummaryInputs,
unorderedEquals(['/tmp/1.sum', '/tmp/2.sum']));
expect(
@@ -71,10 +65,10 @@
outSink.writeln('outSink b');
errorSink.writeln('errorSink b');
}).run();
- expect(connection.outputList, hasLength(1));
+ expect(connection.responses, hasLength(1));
- var response = connection.outputList[0];
- expect(response.exitCode, WorkerLoop.EXIT_CODE_OK);
+ var response = connection.responses[0];
+ expect(response.exitCode, EXIT_CODE_OK, reason: response.output);
expect(
response.output,
allOf(contains('errorSink a'), contains('errorSink a'),
@@ -89,64 +83,53 @@
var request = new WorkRequest();
request.arguments.addAll(['--unknown-option', '/foo.dart', '/bar.dart']);
stdinStream.addInputBytes(_serializeProto(request));
- new _TestWorkerLoop(connection).run();
- expect(connection.outputList, hasLength(1));
+ stdinStream.close();
+ new TestAnalyzerWorkerLoop(connection).run();
+ expect(connection.responses, hasLength(1));
- var response = connection.outputList[0];
- expect(response.exitCode, WorkerLoop.EXIT_CODE_ERROR);
+ var response = connection.responses[0];
+ expect(response.exitCode, EXIT_CODE_ERROR);
expect(response.output, anything);
}
test_run_invalidRequest_noArgumentsInputs() {
stdinStream.addInputBytes(_serializeProto(new WorkRequest()));
+ stdinStream.close();
- new _TestWorkerLoop(connection).run();
- expect(connection.outputList, hasLength(1));
+ new TestAnalyzerWorkerLoop(connection).run();
+ expect(connection.responses, hasLength(1));
- var response = connection.outputList[0];
- expect(response.exitCode, WorkerLoop.EXIT_CODE_ERROR);
+ var response = connection.responses[0];
+ expect(response.exitCode, EXIT_CODE_ERROR);
expect(response.output, anything);
}
test_run_invalidRequest_randomBytes() {
stdinStream.addInputBytes([1, 2, 3]);
- new _TestWorkerLoop(connection).run();
- expect(connection.outputList, hasLength(1));
+ stdinStream.close();
+ new TestAnalyzerWorkerLoop(connection).run();
+ expect(connection.responses, hasLength(1));
- var response = connection.outputList[0];
- expect(response.exitCode, WorkerLoop.EXIT_CODE_ERROR);
+ var response = connection.responses[0];
+ expect(response.exitCode, EXIT_CODE_ERROR);
expect(response.output, anything);
}
test_run_stopAtEOF() {
- stdinStream.addInputBytes([-1]);
- new _TestWorkerLoop(connection).run();
+ stdinStream.close();
+ new TestAnalyzerWorkerLoop(connection).run();
}
}
-/**
- * A [StdWorkerConnection] which records its responses.
- */
-class _TestWorkerConnection extends StdWorkerConnection {
- final outputList = <WorkResponse>[];
-
- _TestWorkerConnection(Stdin stdinStream, Stdout stdoutStream)
- : super(stdinStream, stdoutStream);
-
- @override
- void writeResponse(WorkResponse response) {
- super.writeResponse(response);
- outputList.add(response);
- }
-}
+typedef void _TestWorkerLoopAnalyze(CommandLineOptions options);
/**
- * [WorkerLoop] for testing.
+ * [AnalyzerWorkerLoop] for testing.
*/
-class _TestWorkerLoop extends WorkerLoop {
+class TestAnalyzerWorkerLoop extends AnalyzerWorkerLoop {
final _TestWorkerLoopAnalyze _analyze;
- _TestWorkerLoop(WorkerConnection connection, [this._analyze])
+ TestAnalyzerWorkerLoop(SyncWorkerConnection connection, [this._analyze])
: super(connection);
@override
diff --git a/pkg/analyzer_cli/test/message_grouper_test.dart b/pkg/analyzer_cli/test/message_grouper_test.dart
deleted file mode 100644
index 6388f9b..0000000
--- a/pkg/analyzer_cli/test/message_grouper_test.dart
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer_cli/src/message_grouper.dart';
-import 'package:unittest/unittest.dart';
-
-import 'utils.dart';
-
-main() {
- MessageGrouper messageGrouper;
- TestStdinStream stdinStream;
-
- setUp(() {
- stdinStream = new TestStdinStream();
- messageGrouper = new MessageGrouper(stdinStream);
- });
-
- group('message_grouper', () {
- /// Check that if the message grouper produces the [expectedOutput] in
- /// response to the corresponding [input].
- void check(List<int> input, List<List<int>> expectedOutput) {
- stdinStream.addInputBytes(input);
- for (var chunk in expectedOutput) {
- expect(messageGrouper.next, equals(chunk));
- }
- }
-
- /// Make a simple message having the given [length]
- List<int> makeMessage(int length) {
- var result = <int>[];
- for (int i = 0; i < length; i++) {
- result.add(i & 0xff);
- }
- return result;
- }
-
- test('Empty message', () {
- check([0], [[]]);
- });
-
- test('Short message', () {
- check([
- 5,
- 10,
- 20,
- 30,
- 40,
- 50
- ], [
- [10, 20, 30, 40, 50]
- ]);
- });
-
- test('Message with 2-byte length', () {
- var len = 0x155;
- var msg = makeMessage(len);
- var encodedLen = [0xd5, 0x02];
- check([]..addAll(encodedLen)..addAll(msg), [msg]);
- });
-
- test('Message with 3-byte length', () {
- var len = 0x4103;
- var msg = makeMessage(len);
- var encodedLen = [0x83, 0x82, 0x01];
- check([]..addAll(encodedLen)..addAll(msg), [msg]);
- });
-
- test('Multiple messages', () {
- check([
- 2,
- 10,
- 20,
- 2,
- 30,
- 40
- ], [
- [10, 20],
- [30, 40]
- ]);
- });
-
- test('Empty message at start', () {
- check([
- 0,
- 2,
- 10,
- 20
- ], [
- [],
- [10, 20]
- ]);
- });
-
- test('Empty message at end', () {
- check([
- 2,
- 10,
- 20,
- 0
- ], [
- [10, 20],
- []
- ]);
- });
-
- test('Empty message in the middle', () {
- check([
- 2,
- 10,
- 20,
- 0,
- 2,
- 30,
- 40
- ], [
- [10, 20],
- [],
- [30, 40]
- ]);
- });
- });
-}
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 6b546a6..620c047 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -32,7 +32,6 @@
expect(options.displayVersion, isFalse);
expect(options.enableStrictCallChecks, isFalse);
expect(options.enableSuperMixins, isFalse);
- expect(options.enableConditionalDirectives, isFalse);
expect(options.enableTypeChecks, isFalse);
expect(options.hintsAreFatal, isFalse);
expect(options.ignoreUnrecognizedFlags, isFalse);
diff --git a/pkg/analyzer_cli/test/utils.dart b/pkg/analyzer_cli/test/utils.dart
index ce71009b..07dbe4b 100644
--- a/pkg/analyzer_cli/test/utils.dart
+++ b/pkg/analyzer_cli/test/utils.dart
@@ -4,7 +4,6 @@
library analyzer_cli.test.utils;
-import 'dart:collection';
import 'dart:io';
import 'dart:mirrors';
@@ -12,7 +11,6 @@
import 'package:analyzer/src/generated/java_io.dart';
import 'package:path/path.dart' as pathos;
import 'package:path/path.dart' as path;
-import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
/// Gets the test directory in a way that works with
@@ -65,37 +63,3 @@
}
class _TestUtils {}
-
-/**
- * A [Stdin] mock.
- */
-class TestStdinStream extends TypedMock implements Stdin {
- final pendingBytes = new Queue<int>();
-
- // Adds all the input bytes to this stream.
- void addInputBytes(List<int> bytes) {
- pendingBytes.addAll(bytes);
- }
-
- @override
- int readByteSync() {
- if (pendingBytes.isEmpty) {
- return -1;
- } else {
- return pendingBytes.removeFirst();
- }
- }
-}
-
-/**
- * A [Stdout] mock.
- */
-class TestStdoutStream extends TypedMock implements Stdout {
- final writes = <List<int>>[];
-
- @override
- void add(List<int> bytes) {
- super.add(bytes);
- writes.add(bytes);
- }
-}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index bfadc5b..d360c18 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -14,8 +14,10 @@
import 'package:package_config/src/util.dart' show checkValidPackageUri;
import '../compiler_new.dart' as api;
+import 'common/tasks.dart' show GenericTask, Measurer;
import 'common.dart';
-import 'common/tasks.dart' show GenericTask;
+import 'common/backend_api.dart' show
+ Backend;
import 'compiler.dart';
import 'diagnostics/messages.dart' show Message;
import 'elements/elements.dart' as elements;
@@ -23,6 +25,7 @@
import 'io/source_file.dart';
import 'options.dart' show CompilerOptions;
import 'platform_configuration.dart' as platform_configuration;
+import 'resolved_uri_translator.dart';
import 'script.dart';
/// Implements the [Compiler] using a [api.CompilerInput] for supplying the
@@ -31,12 +34,12 @@
api.CompilerInput provider;
api.CompilerDiagnostics handler;
Packages packages;
- bool mockableLibraryUsed = false;
- /// A mapping of the dart: library-names to their location.
- ///
- /// Initialized in [setupSdk].
- Map<String, Uri> sdkLibraries;
+ bool get mockableLibraryUsed => resolvedUriTranslator.isSet
+ ? resolvedUriTranslator.mockableLibraryUsed
+ : false;
+
+ ForwardingResolvedUriTranslator resolvedUriTranslator;
GenericTask userHandlerTask;
GenericTask userProviderTask;
@@ -45,11 +48,14 @@
Uri get libraryRoot => options.platformConfigUri.resolve(".");
CompilerImpl(this.provider, api.CompilerOutput outputProvider, this.handler,
- CompilerOptions options)
- : super(
+ CompilerOptions options,
+ {MakeBackendFuncion makeBackend, MakeReporterFunction makeReporter})
+ : resolvedUriTranslator = new ForwardingResolvedUriTranslator(),
+ super(
options: options,
outputProvider: outputProvider,
- environment: new _Environment(options.environment)) {
+ environment: new _Environment(options.environment),
+ makeBackend: makeBackend, makeReporter: makeReporter) {
_Environment env = environment;
env.compiler = this;
tasks.addAll([
@@ -64,15 +70,6 @@
null, null, null, null, message, api.Diagnostic.VERBOSE_INFO);
}
- /// See [Compiler.translateResolvedUri].
- Uri translateResolvedUri(elements.LibraryElement importingLibrary,
- Uri resolvedUri, Spannable spannable) {
- if (resolvedUri.scheme == 'dart') {
- return translateDartUri(importingLibrary, resolvedUri, spannable);
- }
- return resolvedUri;
- }
-
/**
* Reads the script designated by [readableUri].
*/
@@ -149,63 +146,6 @@
Uri translateUri(Spannable node, Uri uri) =>
uri.scheme == 'package' ? translatePackageUri(node, uri) : uri;
- /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative
- /// to `options.platformConfigUri` according to the information in the file at
- /// `options.platformConfigUri`.
- ///
- /// Returns null and emits an error if the library could not be found or
- /// imported into [importingLibrary].
- ///
- /// Internal libraries (whose name starts with '_') can be only resolved if
- /// [importingLibrary] is a platform or patch library.
- Uri translateDartUri(elements.LibraryElement importingLibrary,
- Uri resolvedUri, Spannable spannable) {
- Uri location = lookupLibraryUri(resolvedUri.path);
-
- if (location == null) {
- reporter.reportErrorMessage(spannable, MessageKind.LIBRARY_NOT_FOUND,
- {'resolvedUri': resolvedUri});
- return null;
- }
-
- if (resolvedUri.path.startsWith('_')) {
- bool allowInternalLibraryAccess = importingLibrary != null &&
- (importingLibrary.isPlatformLibrary ||
- importingLibrary.isPatch ||
- importingLibrary.canonicalUri.path
- .contains('sdk/tests/compiler/dart2js_native'));
-
- if (!allowInternalLibraryAccess) {
- if (importingLibrary != null) {
- reporter.reportErrorMessage(
- spannable, MessageKind.INTERNAL_LIBRARY_FROM, {
- 'resolvedUri': resolvedUri,
- 'importingUri': importingLibrary.canonicalUri
- });
- } else {
- reporter.reportErrorMessage(spannable, MessageKind.INTERNAL_LIBRARY,
- {'resolvedUri': resolvedUri});
- registerDisallowedLibraryUse(resolvedUri);
- }
- return null;
- }
- }
-
- if (location.scheme == "unsupported") {
- reporter.reportErrorMessage(spannable, MessageKind.LIBRARY_NOT_SUPPORTED,
- {'resolvedUri': resolvedUri});
- registerDisallowedLibraryUse(resolvedUri);
- return null;
- }
-
- if (resolvedUri.path == 'html' || resolvedUri.path == 'io') {
- // TODO(ahe): Get rid of mockableLibraryUsed when test.dart
- // supports this use case better.
- mockableLibraryUsed = true;
- }
- return location;
- }
-
Uri translatePackageUri(Spannable node, Uri uri) {
try {
checkValidPackageUri(uri);
@@ -223,14 +163,14 @@
Future<elements.LibraryElement> analyzeUri(Uri uri,
{bool skipLibraryWithPartOfTag: true}) {
- List<Future> setupFutures = new List<Future>();
- if (sdkLibraries == null) {
- setupFutures.add(setupSdk());
+ Future setupFuture = new Future.value();
+ if (resolvedUriTranslator.isNotSet) {
+ setupFuture = setupFuture.then((_) => setupSdk());
}
if (packages == null) {
- setupFutures.add(setupPackages(uri));
+ setupFuture = setupFuture.then((_) => setupPackages(uri));
}
- return Future.wait(setupFutures).then((_) {
+ return setupFuture.then((_) {
return super
.analyzeUri(uri, skipLibraryWithPartOfTag: skipLibraryWithPartOfTag);
});
@@ -273,11 +213,12 @@
}
Future<Null> setupSdk() {
- if (sdkLibraries == null) {
+ if (resolvedUriTranslator.isNotSet) {
return platform_configuration
.load(options.platformConfigUri, provider)
.then((Map<String, Uri> mapping) {
- sdkLibraries = mapping;
+ resolvedUriTranslator.resolvedUriTranslator =
+ new ResolvedUriTranslator(mapping, reporter);
});
} else {
// The incremental compiler sets up the sdk before run.
@@ -287,33 +228,59 @@
}
Future<bool> run(Uri uri) {
- log('Using platform configuration at ${options.platformConfigUri}');
+ Duration setupDuration = measurer.wallClock.elapsed;
+ return selfTask.measureSubtask("CompilerImpl.run", () {
+ log('Using platform configuration at ${options.platformConfigUri}');
- return Future.wait([setupSdk(), setupPackages(uri)]).then((_) {
- assert(sdkLibraries != null);
- assert(packages != null);
+ return setupSdk().then((_) => setupPackages(uri)).then((_) {
+ assert(resolvedUriTranslator.isSet);
+ assert(packages != null);
- 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');
- for (String subtask in task.subtasks) {
- int subtime = task.getSubtaskTime(subtask);
- log('${task.name} > $subtask took ${subtime}msec');
- }
- }
+ return super.run(uri);
+ }).then((bool success) {
+ if (options.verbose) {
+ StringBuffer timings = new StringBuffer();
+ computeTimings(setupDuration, timings);
+ log("$timings");
}
- int total = totalCompileTime.elapsedMilliseconds;
- log('Total compile-time ${total}msec;'
- ' unaccounted ${total - cumulated}msec');
return success;
});
});
}
+ void computeTimings(Duration setupDuration, StringBuffer timings) {
+ timings.writeln("Timings:");
+ Duration totalDuration = measurer.wallClock.elapsed;
+ Duration asyncDuration = measurer.asyncWallClock.elapsed;
+ Duration cumulatedDuration = Duration.ZERO;
+ for (final task in tasks) {
+ String running = task.isRunning ? "*" : "";
+ Duration duration = task.duration;
+ if (duration != Duration.ZERO) {
+ cumulatedDuration += duration;
+ timings.writeln(
+ ' $running${task.name} took'
+ ' ${duration.inMilliseconds}msec');
+ for (String subtask in task.subtasks) {
+ int subtime = task.getSubtaskTime(subtask);
+ String running = task.getSubtaskIsRunning(subtask) ? "*" : "";
+ timings.writeln(
+ ' $running${task.name} > $subtask took ${subtime}msec');
+ }
+ }
+ }
+ Duration unaccountedDuration =
+ totalDuration - cumulatedDuration - setupDuration - asyncDuration;
+ double percent = unaccountedDuration.inMilliseconds * 100
+ / totalDuration.inMilliseconds;
+ timings.write(
+ ' Total compile-time ${totalDuration.inMilliseconds}msec;'
+ ' setup ${setupDuration.inMilliseconds}msec;'
+ ' async ${asyncDuration.inMilliseconds}msec;'
+ ' unaccounted ${unaccountedDuration.inMilliseconds}msec'
+ ' (${percent.toStringAsFixed(2)}%)');
+ }
+
void reportDiagnostic(DiagnosticMessage message,
List<DiagnosticMessage> infos, api.Diagnostic kind) {
_reportDiagnosticMessage(message, kind);
@@ -341,24 +308,33 @@
void callUserHandler(Message message, Uri uri, int begin, int end,
String text, api.Diagnostic kind) {
- userHandlerTask.measure(() {
- handler.report(message, uri, begin, end, text, kind);
- });
+ try {
+ userHandlerTask.measure(() {
+ handler.report(message, uri, begin, end, text, kind);
+ });
+ } catch (ex, s) {
+ reportCrashInUserCode('Uncaught exception in diagnostic handler', ex, s);
+ rethrow;
+ }
}
Future callUserProvider(Uri uri) {
- return userProviderTask.measure(() => provider.readFromUri(uri));
+ try {
+ return userProviderTask.measureIo(() => provider.readFromUri(uri));
+ } catch (ex, s) {
+ reportCrashInUserCode('Uncaught exception in input provider', ex, s);
+ rethrow;
+ }
}
Future<Packages> callUserPackagesDiscovery(Uri uri) {
- return userPackagesDiscoveryTask
- .measure(() => options.packagesDiscoveryProvider(uri));
- }
-
- Uri lookupLibraryUri(String libraryName) {
- assert(invariant(NO_LOCATION_SPANNABLE, sdkLibraries != null,
- message: "setupSdk() has not been run"));
- return sdkLibraries[libraryName];
+ try {
+ return userPackagesDiscoveryTask
+ .measureIo(() => options.packagesDiscoveryProvider(uri));
+ } catch (ex, s) {
+ reportCrashInUserCode('Uncaught exception in package discovery', ex, s);
+ rethrow;
+ }
}
Uri resolvePatchUri(String libraryName) {
@@ -370,14 +346,15 @@
final Map<String, String> definitions;
// TODO(sigmund): break the circularity here: Compiler needs an environment to
- // intialize the library loader, but the environment here needs to know about
+ // initialize the library loader, but the environment here needs to know about
// how the sdk is set up and about whether the backend supports mirrors.
CompilerImpl compiler;
_Environment(this.definitions);
String valueOf(String name) {
- assert(invariant(NO_LOCATION_SPANNABLE, compiler.sdkLibraries != null,
+ assert(invariant(
+ NO_LOCATION_SPANNABLE, compiler.resolvedUriTranslator != null,
message: "setupSdk() has not been run"));
var result = definitions[name];
@@ -389,7 +366,7 @@
// Private libraries are not exposed to the users.
if (libraryName.startsWith("_")) return null;
- if (compiler.sdkLibraries.containsKey(libraryName)) {
+ if (compiler.resolvedUriTranslator.sdkLibraries.containsKey(libraryName)) {
// Dart2js always "supports" importing 'dart:mirrors' but will abort
// the compilation at a later point if the backend doesn't support
// mirrors. In this case 'mirrors' should not be in the environment.
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 2d0ee99..dfb5ba9 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -6,7 +6,7 @@
import 'common.dart';
import 'common/names.dart' show Identifiers;
-import 'common/resolution.dart' show Parsing, Resolution;
+import 'common/resolution.dart' show ParsingContext, Resolution;
import 'common/tasks.dart' show CompilerTask;
import 'compiler.dart' show Compiler;
import 'constants/expressions.dart';
@@ -30,9 +30,15 @@
String get name => "Closure Simplifier";
- ClosureClassMap computeClosureToClassMapping(
- Element element, Node node, TreeElements elements) {
+ ClosureClassMap computeClosureToClassMapping(ResolvedAst resolvedAst) {
return measure(() {
+ Element element = resolvedAst.element;
+ if (resolvedAst.kind != ResolvedAstKind.PARSED) {
+ return new ClosureClassMap(null, null, null, new ThisLocal(element));
+ }
+ Node node = resolvedAst.node;
+ TreeElements elements = resolvedAst.elements;
+
ClosureClassMap cached = closureMappingCache[node];
if (cached != null) return cached;
@@ -44,6 +50,8 @@
if (node is FunctionExpression) {
translator.translateFunction(element, node);
} else if (element.isSynthesized) {
+ reporter.internalError(
+ element, "Unexpected synthesized element: $element");
return new ClosureClassMap(null, null, null, new ThisLocal(element));
} else {
assert(element.isField);
@@ -123,7 +131,7 @@
bool get hasResolvedAst => hasTreeElements;
ResolvedAst get resolvedAst {
- return new ResolvedAst(this, null, treeElements);
+ return new ParsedResolvedAst(this, null, null, treeElements);
}
Expression get initializer {
@@ -185,7 +193,7 @@
// By assigning a fresh class-id we make sure that the hashcode
// is unique, but also emit closure classes after all other
// classes (since the emitter sorts classes by their id).
- compiler.getNextFreeId(),
+ compiler.idGenerator.getNextFreeId(),
STATE_DONE) {
JavaScriptBackend backend = compiler.backend;
ClassElement superclass = methodElement.isInstanceMember
@@ -213,7 +221,7 @@
Token get position => node.getBeginToken();
- Node parseNode(Parsing parsing) => node;
+ Node parseNode(ParsingContext parsing) => node;
// A [ClosureClassElement] is nested inside a function or initializer in terms
// of [enclosingElement], but still has to be treated as a top-level
@@ -335,10 +343,10 @@
FunctionExpression get node => expression.node;
- FunctionExpression parseNode(Parsing parsing) => node;
+ FunctionExpression parseNode(ParsingContext parsing) => node;
ResolvedAst get resolvedAst {
- return new ResolvedAst(this, node, treeElements);
+ return new ParsedResolvedAst(this, node, node.body, treeElements);
}
Element get analyzableElement => closureClass.methodElement.analyzableElement;
@@ -371,6 +379,27 @@
f(LocalVariableElement variable, BoxFieldElement boxField)) {
capturedVariables.forEach(f);
}
+
+ String toString() {
+ String separator = '';
+ StringBuffer sb = new StringBuffer();
+ sb.write('ClosureScope(');
+ if (boxElement != null) {
+ sb.write('box=$boxElement');
+ separator = ',';
+ }
+ if (boxedLoopVariables.isNotEmpty) {
+ sb.write(separator);
+ sb.write('boxedLoopVariables=${boxedLoopVariables}');
+ separator = ',';
+ }
+ if (capturedVariables.isNotEmpty) {
+ sb.write(separator);
+ sb.write('capturedVariables=$capturedVariables');
+ }
+ sb.write(')');
+ return sb.toString();
+ }
}
class ClosureClassMap {
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 71a8c82..6b809e9 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -8,43 +8,44 @@
import '../common.dart';
import '../common/codegen.dart' show CodegenImpact;
-import '../common/resolution.dart' show ResolutionImpact;
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart' show ResolutionImpact, Frontend;
import '../compile_time_constants.dart'
show BackendConstantEnvironment, ConstantCompilerTask;
-import '../constants/expressions.dart' show ConstantExpression;
+import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart' show ConstantSystem;
+import '../constants/expressions.dart' show ConstantExpression;
import '../constants/values.dart' show ConstantValue;
import '../dart_types.dart' show DartType, InterfaceType;
import '../elements/elements.dart'
show
ClassElement,
- ConstructorElement,
Element,
FunctionElement,
LibraryElement,
MetadataAnnotation,
MethodElement;
-import '../enqueue.dart' show Enqueuer, CodegenEnqueuer, ResolutionEnqueuer;
+import '../enqueue.dart' show Enqueuer, EnqueueTask, CodegenEnqueuer, ResolutionEnqueuer;
import '../io/code_output.dart' show CodeBuffer;
import '../io/source_information.dart' show SourceInformationStrategy;
import '../js_backend/backend_helpers.dart' as js_backend show BackendHelpers;
-import '../js_backend/js_backend.dart' as js_backend show JavaScriptBackend;
+import '../js_backend/js_backend.dart' as js_backend;
import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
import '../native/native.dart' as native show NativeEnqueuer, maybeEnableNative;
import '../patch_parser.dart'
show checkNativeAnnotation, checkJsInteropAnnotation;
-import '../resolution/tree_elements.dart' show TreeElements;
import '../serialization/serialization.dart'
- show DeserializerPlugin, ObjectDecoder, ObjectEncoder, SerializerPlugin;
+ show DeserializerPlugin, SerializerPlugin;
import '../tree/tree.dart' show Node, Send;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/world_impact.dart' show ImpactStrategy, WorldImpact;
-
-import 'codegen.dart' show CodegenWorkItem;
-import 'registry.dart' show Registry;
-import 'tasks.dart' show CompilerTask;
-import 'work.dart' show ItemCompilationContext;
+import 'codegen.dart' show
+ CodegenWorkItem;
+import 'registry.dart' show
+ Registry;
+import 'tasks.dart' show
+ CompilerTask;
+import 'work.dart' show
+ ItemCompilationContext;
abstract class Backend {
final Compiler compiler;
@@ -361,9 +362,7 @@
void onCodegenStart() {}
/// Called after [element] has been resolved.
- // TODO(johnniwinther): Change [TreeElements] to [Registry] or a dependency
- // node. [elements] is currently unused by the implementation.
- void onElementResolved(Element element, TreeElements elements) {}
+ void onElementResolved(Element element) {}
// Does this element belong in the output
bool shouldOutput(Element element) => true;
@@ -381,8 +380,10 @@
void registerAsyncMarker(
FunctionElement element, Enqueuer enqueuer, Registry registry) {}
- /// Called when resolving a call to a foreign function.
- void registerForeignCall(Send node, Element element,
+ /// Called when resolving a call to a foreign function. If a non-null value
+ /// is returned, this is stored as native data for [node] in the resolved
+ /// AST.
+ dynamic resolveForeignCall(Send node, Element element,
CallStructure callStructure, ForeignResolver resolver) {}
/// Returns the location of the patch-file associated with [libraryName]
@@ -398,6 +399,11 @@
bool supportSerialization: true}) {
return const ImpactStrategy();
}
+
+ /// Backend access to the front-end.
+ Frontend get frontend => compiler.resolution;
+
+ EnqueueTask makeEnqueuer() => new EnqueueTask(compiler);
}
/// Interface for resolving calls to foreign functions.
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 0a9cf75..4640bdb 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -4,6 +4,7 @@
library dart2js.common.codegen;
+import '../closure.dart' show SynthesizedCallMethodElementX;
import '../common.dart';
import '../compiler.dart' show Compiler;
import '../constants/values.dart' show ConstantValue;
@@ -14,9 +15,9 @@
ClassElement,
Element,
FunctionElement,
- LocalFunctionElement;
+ LocalFunctionElement,
+ ResolvedAst;
import '../enqueue.dart' show CodegenEnqueuer;
-import '../resolution/tree_elements.dart' show TreeElements;
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
import '../universe/world_impact.dart'
show WorldImpact, WorldImpactBuilder, WorldImpactVisitor;
@@ -225,6 +226,7 @@
/// [WorkItem] used exclusively by the [CodegenEnqueuer].
class CodegenWorkItem extends WorkItem {
CodegenRegistry registry;
+ final ResolvedAst resolvedAst;
factory CodegenWorkItem(Compiler compiler, AstElement element,
ItemCompilationContext compilationContext) {
@@ -235,16 +237,14 @@
assert(invariant(
element, compiler.enqueuer.resolution.hasBeenProcessed(element),
message: "$element has not been resolved."));
- assert(invariant(element, element.resolvedAst.elements != null,
- message: 'Resolution tree is null for $element in codegen work item'));
- return new CodegenWorkItem.internal(element, compilationContext);
+ ResolvedAst resolvedAst = compiler.backend.frontend.getResolvedAst(element);
+ return new CodegenWorkItem.internal(resolvedAst, compilationContext);
}
CodegenWorkItem.internal(
- AstElement element, ItemCompilationContext compilationContext)
- : super(element, compilationContext);
-
- TreeElements get resolutionTree => element.resolvedAst.elements;
+ ResolvedAst resolvedAst, ItemCompilationContext compilationContext)
+ : this.resolvedAst = resolvedAst,
+ super(resolvedAst.element, compilationContext);
WorldImpact run(Compiler compiler, CodegenEnqueuer world) {
if (world.isProcessed(element)) return const WorldImpact();
diff --git a/pkg/compiler/lib/src/common/registry.dart b/pkg/compiler/lib/src/common/registry.dart
index 0499858..96ee845 100644
--- a/pkg/compiler/lib/src/common/registry.dart
+++ b/pkg/compiler/lib/src/common/registry.dart
@@ -5,8 +5,8 @@
library dart2js.common.registry;
import '../dart_types.dart' show InterfaceType;
+import '../elements/elements.dart' show Element;
import '../enqueue.dart' show Enqueuer;
-import '../elements/elements.dart' show Element, FunctionElement;
import '../universe/use.dart' show DynamicUse, StaticUse;
/// Interface for registration of element dependencies.
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 42f9617..d049471 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -14,20 +14,19 @@
AstElement,
ClassElement,
Element,
- ErroneousElement,
FunctionElement,
FunctionSignature,
- LocalFunctionElement,
MetadataAnnotation,
- MethodElement,
ResolvedAst,
- TypedefElement,
- TypeVariableElement;
+ TypedefElement;
import '../enqueue.dart' show ResolutionEnqueuer;
import '../options.dart' show ParserOptions;
import '../parser/element_listener.dart' show ScannerOptions;
-import '../tree/tree.dart' show AsyncForIn, Send, TypeAnnotation;
+import '../parser/parser_task.dart';
+import '../patch_parser.dart';
+import '../tree/tree.dart' show TypeAnnotation;
import '../universe/world_impact.dart' show WorldImpact;
+import 'backend_api.dart';
import 'work.dart' show ItemCompilationContext, WorkItem;
/// [WorkItem] used exclusively by the [ResolutionEnqueuer].
@@ -186,9 +185,19 @@
}
}
+/// Interface for the accessing the front-end analysis.
+// TODO(johnniwinther): Find a better name for this.
+abstract class Frontend {
+ /// Returns the `ResolvedAst` for the [element].
+ ResolvedAst getResolvedAst(Element element);
+
+ /// Returns the [ResolutionImpact] for [element].
+ ResolutionImpact getResolutionImpact(Element element);
+}
+
// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
-abstract class Resolution {
- Parsing get parsing;
+abstract class Resolution implements Frontend {
+ ParsingContext get parsingContext;
DiagnosticReporter get reporter;
CoreTypes get coreTypes;
@@ -203,8 +212,15 @@
FunctionSignature resolveSignature(FunctionElement function);
DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
+ /// Returns `true` if [element] has been resolved.
+ // TODO(johnniwinther): Normalize semantics between normal and deserialized
+ // elements; deserialized elements are always resolved but the method will
+ // return `false`.
bool hasBeenResolved(Element element);
+ /// Resolve [element] if it has not already been resolved.
+ void ensureResolved(Element element);
+
ResolutionWorkItem createWorkItem(
Element element, ItemCompilationContext compilationContext);
@@ -220,6 +236,9 @@
/// Returns the precomputed [ResolutionImpact] for [element].
ResolutionImpact getResolutionImpact(Element element);
+ /// Returns the [ResolvedAst] for [element], computing it if necessary.
+ ResolvedAst computeResolvedAst(Element element);
+
/// Returns the precomputed [WorldImpact] for [element].
WorldImpact getWorldImpact(Element element);
@@ -234,13 +253,59 @@
/// Later calls to [getWorldImpact] or [computeWorldImpact] returns an empty
/// impact.
void emptyCache();
+
+ void forgetElement(Element element);
}
-// TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.
-abstract class Parsing {
+/// A container of commonly used dependencies for tasks that involve parsing.
+abstract class ParsingContext {
+ factory ParsingContext(
+ DiagnosticReporter reporter,
+ ParserOptions parserOptions,
+ ParserTask parser,
+ PatchParserTask patchParser,
+ Backend backend) = _ParsingContext;
+
DiagnosticReporter get reporter;
- void parsePatchClass(ClassElement cls);
- measure(f());
- ScannerOptions getScannerOptionsFor(Element element);
ParserOptions get parserOptions;
+ ParserTask get parser;
+ PatchParserTask get patchParser;
+
+ /// Use [patchParser] directly instead.
+ @deprecated
+ void parsePatchClass(ClassElement cls);
+
+ /// Use [parser] and measure directly instead.
+ @deprecated
+ measure(f());
+
+ /// Get the [ScannerOptions] to scan the given [element].
+ ScannerOptions getScannerOptionsFor(Element element);
+}
+
+class _ParsingContext implements ParsingContext {
+ final DiagnosticReporter reporter;
+ final ParserOptions parserOptions;
+ final ParserTask parser;
+ final PatchParserTask patchParser;
+ final Backend backend;
+
+ _ParsingContext(this.reporter, this.parserOptions, this.parser,
+ this.patchParser, this.backend);
+
+ @override
+ measure(f()) => parser.measure(f);
+
+ @override
+ void parsePatchClass(ClassElement cls) {
+ patchParser.measure(() {
+ if (cls.isPatch) {
+ patchParser.parsePatchClassNode(cls);
+ }
+ });
+ }
+
+ @override
+ ScannerOptions getScannerOptionsFor(Element element) => new ScannerOptions(
+ canUseNative: backend.canLibraryUseNative(element.library));
}
diff --git a/pkg/compiler/lib/src/common/tasks.dart b/pkg/compiler/lib/src/common/tasks.dart
index 69e5f11..c5a77d3 100644
--- a/pkg/compiler/lib/src/common/tasks.dart
+++ b/pkg/compiler/lib/src/common/tasks.dart
@@ -4,7 +4,12 @@
library dart2js.common.tasks;
-import 'dart:developer' show UserTag;
+import 'dart:async' show
+ Future,
+ Zone,
+ ZoneDelegate,
+ ZoneSpecification,
+ runZoned;
import '../common.dart';
import '../compiler.dart' show Compiler;
@@ -19,20 +24,27 @@
DeferredTask(this.element, this.action);
}
+/// A [CompilerTask] is used to measure where time is spent in the compiler.
+/// The main entry points are [measure] and [measureIo].
class CompilerTask {
final Compiler compiler;
final Stopwatch watch;
- UserTag profilerTag;
final Map<String, GenericTask> _subtasks = <String, GenericTask>{};
+ int asyncCount = 0;
+
CompilerTask(Compiler compiler)
: this.compiler = compiler,
watch = (compiler.options.verbose) ? new Stopwatch() : null;
DiagnosticReporter get reporter => compiler.reporter;
+ Measurer get measurer => compiler.measurer;
+
String get name => "Unknown task '${this.runtimeType}'";
+ bool get isRunning => watch?.isRunning == true;
+
int get timing {
if (watch == null) return 0;
int total = watch.elapsedMilliseconds;
@@ -42,38 +54,161 @@
return total;
}
- UserTag getProfilerTag() {
- if (profilerTag == null) profilerTag = new UserTag(name);
- return profilerTag;
- }
-
- measure(action()) {
- // In verbose mode when watch != null.
- if (watch == null) return action();
- CompilerTask previous = compiler.measuredTask;
- if (identical(this, previous)) return action();
- compiler.measuredTask = this;
- if (previous != null) previous.watch.stop();
- watch.start();
- UserTag oldTag = getProfilerTag().makeCurrent();
- try {
- return action();
- } finally {
- watch.stop();
- oldTag.makeCurrent();
- if (previous != null) previous.watch.start();
- compiler.measuredTask = previous;
+ Duration get duration {
+ if (watch == null) return Duration.ZERO;
+ Duration total = watch.elapsed;
+ for (GenericTask subtask in _subtasks.values) {
+ total += subtask.duration;
}
+ return total;
}
+ /// Perform [action] and use [watch] to measure its runtime (including any
+ /// asynchronous callbacks, such as, [Future.then], but excluding code
+ /// measured by other tasks).
+ measure(action()) => watch == null ? action() : measureZoned(action);
+
+ /// Helper method that starts measuring with this [CompilerTask], that is,
+ /// make this task the currently measured task.
+ CompilerTask start() {
+ if (watch == null) return null;
+ CompilerTask previous = measurer.currentTask;
+ measurer.currentTask = this;
+ if (previous != null) previous.watch.stop();
+ // Regardless of whether [previous] is `null` we've returned from the
+ // eventloop.
+ measurer.stopAsyncWallClock();
+ watch.start();
+ return previous;
+ }
+
+ /// Helper method that stops measuring with this [CompilerTask], that is,
+ /// make [previous] the currently measured task.
+ void stop(CompilerTask previous) {
+ if (watch == null) return;
+ watch.stop();
+ if (previous != null) {
+ previous.watch.start();
+ } else {
+ // If there's no previous task, we're about to return control to the
+ // event loop. Start counting that as waiting asynchronous I/O.
+ measurer.startAsyncWallClock();
+ }
+ measurer.currentTask = previous;
+ }
+
+ /// Helper method for [measure]. Don't call this method directly as it
+ /// assumes that [watch] isn't null.
+ measureZoned(action()) {
+ // Using zones, we're able to track asynchronous operations correctly, as
+ // our zone will be asked to invoke `then` blocks. Then blocks (the closure
+ // passed to runZoned, and other closures) are run via the `run` functions
+ // below.
+
+ assert(watch != null);
+
+ // The current zone is already measuring `this` task.
+ if (Zone.current[measurer] == this) return action();
+
+ /// Run [f] in [zone]. Running must be delegated to [parent] to ensure that
+ /// various state is set up correctly (in particular that `Zone.current`
+ /// has the right value). Since [measureZoned] can be called recursively
+ /// (synchronously), some of the measuring zones we create will be parents
+ /// of other measuring zones, but we still need to call through the parent
+ /// chain. Consequently, we use a zone value keyed by [measurer] to see if
+ /// we should measure or not when delegating.
+ run(Zone self, ZoneDelegate parent, Zone zone, f()) {
+ if (zone[measurer] != this) return parent.run(zone, f);
+ CompilerTask previous = start();
+ try {
+ return parent.run(zone, f);
+ } finally {
+ stop(previous);
+ }
+ }
+
+ /// Same as [run] except that [f] takes one argument, [arg].
+ runUnary(Zone self, ZoneDelegate parent, Zone zone, f(arg), arg) {
+ if (zone[measurer] != this) return parent.runUnary(zone, f, arg);
+ CompilerTask previous = start();
+ try {
+ return parent.runUnary(zone, f, arg);
+ } finally {
+ stop(previous);
+ }
+ }
+
+ /// Same as [run] except that [f] takes two arguments ([a1] and [a2]).
+ runBinary(Zone self, ZoneDelegate parent, Zone zone, f(a1, a2), a1, a2) {
+ if (zone[measurer] != this) return parent.runBinary(zone, f, a1, a2);
+ CompilerTask previous = start();
+ try {
+ return parent.runBinary(zone, f, a1, a2);
+ } finally {
+ stop(previous);
+ }
+ }
+
+ return runZoned(
+ action,
+ zoneValues: { measurer: this },
+ zoneSpecification: new ZoneSpecification(
+ run: run, runUnary: runUnary, runBinary: runBinary));
+ }
+
+ /// Asynchronous version of [measure]. Use this when action returns a future
+ /// that's truly asynchronous, such I/O. Only one task can use this method
+ /// concurrently.
+ ///
+ /// Note: we assume that this method is used only by the compiler input
+ /// provider, but it could be used by other tasks as long as the input
+ /// provider will not be called by those tasks.
+ measureIo(Future action()) {
+ return watch == null ? action() : measureIoHelper(action);
+ }
+
+ /// Helper method for [measureIo]. Don't call this directly as it assumes
+ /// that [watch] isn't null.
+ Future measureIoHelper(Future action()) {
+ assert(watch != null);
+ if (measurer.currentAsyncTask == null) {
+ measurer.currentAsyncTask = this;
+ } else if (measurer.currentAsyncTask != this) {
+ throw "Can't track async task '$name' because"
+ " '${measurer.currentAsyncTask.name}' is already being tracked.";
+ }
+ asyncCount++;
+ return measure(action).whenComplete(() {
+ asyncCount--;
+ if (asyncCount == 0) measurer.currentAsyncTask = null;
+ });
+ }
+
+ /// Convenience function for combining
+ /// [DiagnosticReporter.withCurrentElement] and [measure].
measureElement(Element element, action()) {
- reporter.withCurrentElement(element, () => measure(action));
+ return watch == null
+ ? reporter.withCurrentElement(element, action)
+ : measureElementHelper(element, action);
+ }
+
+ /// Helper method for [measureElement]. Don't call this directly as it
+ /// assumes that [watch] isn't null.
+ measureElementHelper(Element element, action()) {
+ assert(watch != null);
+ return reporter.withCurrentElement(element, () => measure(action));
}
/// Measure the time spent in [action] (if in verbose mode) and accumulate it
/// under a subtask with the given name.
measureSubtask(String name, action()) {
- if (watch == null) return action();
+ return watch == null ? action() : measureSubtaskHelper(name, action);
+ }
+
+ /// Helper method for [measureSubtask]. Don't call this directly as it
+ /// assumes that [watch] isn't null.
+ measureSubtaskHelper(String name, action()) {
+ assert(watch != null);
// Use a nested CompilerTask for the measurement to ensure nested [measure]
// calls work correctly. The subtasks will never themselves have nested
// subtasks because they are not accessible outside.
@@ -85,6 +220,8 @@
Iterable<String> get subtasks => _subtasks.keys;
int getSubtaskTime(String subtask) => _subtasks[subtask].timing;
+
+ bool getSubtaskIsRunning(String subtask) => _subtasks[subtask].isRunning;
}
class GenericTask extends CompilerTask {
@@ -92,3 +229,48 @@
GenericTask(this.name, Compiler compiler) : super(compiler);
}
+
+class Measurer {
+ /// Measures the total runtime from this object was constructed.
+ ///
+ /// Note: MUST be first field to ensure [wallclock] is started before other
+ /// computations.
+ final Stopwatch wallClock = new Stopwatch()..start();
+
+ /// Measures gaps between zoned closures due to asynchronicity.
+ final Stopwatch asyncWallClock = new Stopwatch();
+
+ /// The currently running task, that is, the task whose [Stopwatch] is
+ /// currently running.
+ CompilerTask currentTask;
+
+ /// The current task which should be charged for asynchronous gaps.
+ CompilerTask currentAsyncTask;
+
+ /// Start counting the total elapsed time since the compiler started.
+ void startWallClock() {
+ wallClock.start();
+ }
+
+ /// Start counting the total elapsed time since the compiler started.
+ void stopWallClock() {
+ wallClock.stop();
+ }
+
+ /// Call this before returning to the eventloop.
+ void startAsyncWallClock() {
+ if (currentAsyncTask != null) {
+ currentAsyncTask.watch.start();
+ } else {
+ asyncWallClock.start();
+ }
+ }
+
+ /// Call this when the eventloop returns control to us.
+ void stopAsyncWallClock() {
+ if (currentAsyncTask != null) {
+ currentAsyncTask.watch.stop();
+ }
+ asyncWallClock.stop();
+ }
+}
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 825176c..c4fe193 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -193,7 +193,7 @@
AstElement currentElement = element.analyzableElement;
return reporter.withCurrentElement(currentElement, () {
// TODO(johnniwinther): Avoid this eager analysis.
- _analyzeElementEagerly(compiler, currentElement);
+ compiler.resolution.ensureResolved(currentElement.declaration);
ConstantExpression constant = compileVariableWithDefinitions(
element, currentElement.resolvedAst.elements,
@@ -847,7 +847,7 @@
// TODO(ahe): This is nasty: we must eagerly analyze the
// constructor to ensure the redirectionTarget has been computed
// correctly. Find a way to avoid this.
- _analyzeElementEagerly(compiler, constructor);
+ resolution.ensureResolved(constructor.declaration);
// The redirection chain of this element may not have been resolved through
// a post-process action, so we have to make sure it is done here.
@@ -1092,6 +1092,7 @@
final ConstructorElement constructor;
final Map<Element, AstConstant> definitions;
final Map<Element, AstConstant> fieldValues;
+ final ResolvedAst resolvedAst;
/**
* Documentation wanted -- johnniwinther
@@ -1103,11 +1104,15 @@
: this.constructor = constructor,
this.definitions = new Map<Element, AstConstant>(),
this.fieldValues = new Map<Element, AstConstant>(),
- super(handler, _analyzeElementEagerly(compiler, constructor), compiler,
- isConst: true) {
+ this.resolvedAst =
+ compiler.resolution.computeResolvedAst(constructor.declaration),
+ super(handler, null, compiler, isConst: true) {
assert(invariant(constructor, constructor.isImplementation));
}
+ @override
+ TreeElements get elements => resolvedAst.elements;
+
AstConstant visitSend(Send send) {
Element element = elements[send];
if (Elements.isLocal(element)) {
@@ -1332,12 +1337,6 @@
new NullConstantValue());
}
-// TODO(johnniwinther): Clean this up.
-TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) {
- compiler.resolution.computeWorldImpact(element.declaration);
- return element.resolvedAst.elements;
-}
-
class _CompilerEnvironment implements Environment {
final Compiler compiler;
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 1b01849..4999d44 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -9,36 +9,29 @@
import '../compiler_new.dart' as api;
import 'cache_strategy.dart' show CacheStrategy;
import 'closure.dart' as closureMapping show ClosureTask;
-import 'common.dart';
import 'common/backend_api.dart' show Backend;
-import 'common/codegen.dart' show CodegenImpact, CodegenWorkItem;
+import 'common/codegen.dart' show CodegenWorkItem;
+import 'common/names.dart' show Selectors;
import 'common/names.dart' show Identifiers, Uris;
import 'common/registry.dart' show EagerRegistry, Registry;
import 'common/resolution.dart'
- show Parsing, Resolution, ResolutionWorkItem, ResolutionImpact;
-import 'common/tasks.dart' show CompilerTask, GenericTask;
+ show ParsingContext, Resolution, ResolutionWorkItem, ResolutionImpact;
+import 'common/tasks.dart' show CompilerTask, GenericTask, Measurer;
import 'common/work.dart' show ItemCompilationContext, WorkItem;
+import 'common.dart';
import 'compile_time_constants.dart';
import 'constants/values.dart';
import 'core_types.dart' show CoreClasses, CoreTypes;
import 'dart_backend/dart_backend.dart' as dart_backend;
import 'dart_types.dart' show DartType, DynamicType, InterfaceType, Types;
-import 'deferred_load.dart' show DeferredLoadTask, OutputUnit;
+import 'deferred_load.dart' show DeferredLoadTask;
import 'diagnostics/code_location.dart';
import 'diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
import 'diagnostics/invariant.dart' show REPORT_EXCESS_RESOLUTION;
import 'diagnostics/messages.dart' show Message, MessageTemplate;
import 'dump_info.dart' show DumpInfoTask;
import 'elements/elements.dart';
-import 'elements/modelx.dart'
- show
- ErroneousElementX,
- ClassElementX,
- CompilationUnitElementX,
- DeferredLoaderGetterElementX,
- MethodElementX,
- LibraryElementX,
- PrefixElementX;
+import 'elements/modelx.dart' show ErroneousElementX;
import 'enqueue.dart'
show
CodegenEnqueuer,
@@ -58,30 +51,27 @@
LibraryLoaderTask,
LoadedLibraries,
LibraryLoaderListener,
- ResolvedUriTranslator,
ScriptLoader;
import 'mirrors_used.dart' show MirrorUsageAnalyzerTask;
-import 'common/names.dart' show Selectors;
import 'null_compiler_output.dart' show NullCompilerOutput, NullSink;
-import 'options.dart' show CompilerOptions, DiagnosticOptions, ParserOptions;
+import 'options.dart' show CompilerOptions, DiagnosticOptions;
import 'parser/diet_parser_task.dart' show DietParserTask;
-import 'parser/element_listener.dart' show ScannerOptions;
import 'parser/parser_task.dart' show ParserTask;
import 'patch_parser.dart' show PatchParserTask;
import 'resolution/registry.dart' show ResolutionRegistry;
import 'resolution/resolution.dart' show ResolverTask;
import 'resolution/tree_elements.dart' show TreeElementMapping;
+import 'resolved_uri_translator.dart';
import 'scanner/scanner_task.dart' show ScannerTask;
-import 'serialization/task.dart' show SerializationTask;
import 'script.dart' show Script;
+import 'serialization/task.dart' show SerializationTask;
import 'ssa/nodes.dart' show HInstruction;
-import 'tracer.dart' show Tracer;
import 'tokens/token.dart' show StringToken, Token, TokenPair;
import 'tokens/token_map.dart' show TokenMap;
+import 'tracer.dart' show Tracer;
import 'tree/tree.dart' show Node, TypeAnnotation;
import 'typechecker.dart' show TypeCheckerTask;
import 'types/types.dart' as ti;
-import 'universe/call_structure.dart' show CallStructure;
import 'universe/selector.dart' show Selector;
import 'universe/universe.dart' show Universe;
import 'universe/use.dart' show StaticUse;
@@ -89,15 +79,25 @@
import 'util/util.dart' show Link, Setlet;
import 'world.dart' show World;
-abstract class Compiler implements LibraryLoaderListener, IdGenerator {
- final Stopwatch totalCompileTime = new Stopwatch();
+typedef Backend MakeBackendFuncion(Compiler compiler);
+
+typedef CompilerDiagnosticReporter MakeReporterFunction(
+ Compiler compiler, CompilerOptions options);
+
+abstract class Compiler implements LibraryLoaderListener {
+ /// Helper instance for measurements in [CompilerTask].
+ ///
+ /// Note: MUST be first field to ensure [Measurer.wallclock] is started
+ /// before other computations.
+ final Measurer measurer = new Measurer();
+
final IdGenerator idGenerator = new IdGenerator();
World world;
Types types;
_CompilerCoreTypes _coreTypes;
- _CompilerDiagnosticReporter _reporter;
+ CompilerDiagnosticReporter _reporter;
_CompilerResolution _resolution;
- _CompilerParsing _parsing;
+ ParsingContext _parsingContext;
final CacheStrategy cacheStrategy;
@@ -141,14 +141,10 @@
List<Uri> librariesToAnalyzeWhenRun;
- /// The set of platform libraries reported as unsupported.
- ///
- /// For instance when importing 'dart:io' without '--categories=Server'.
- Set<Uri> disallowedLibraryUris = new Setlet<Uri>();
+ ResolvedUriTranslator get resolvedUriTranslator;
Tracer tracer;
- CompilerTask measuredTask;
LibraryElement coreLibrary;
LibraryElement asyncLibrary;
@@ -165,7 +161,7 @@
CoreClasses get coreClasses => _coreTypes;
CoreTypes get coreTypes => _coreTypes;
Resolution get resolution => _resolution;
- Parsing get parsing => _parsing;
+ ParsingContext get parsingContext => _parsingContext;
ClassElement typedDataClass;
@@ -179,8 +175,17 @@
// TODO(johnniwinther): Move this to the JavaScriptBackend.
ClassElement nativeAnnotationClass;
- // Initialized after symbolClass has been resolved.
- FunctionElement symbolConstructor;
+ ConstructorElement _symbolConstructor;
+ ConstructorElement get symbolConstructor {
+ if (_symbolConstructor == null) {
+ ClassElement symbolClass = coreClasses.symbolClass;
+ symbolClass.ensureResolved(resolution);
+ _symbolConstructor = symbolClass.lookupConstructor('');
+ assert(invariant(symbolClass, _symbolConstructor != null,
+ message: "Default constructor not found ${symbolClass}."));
+ }
+ return _symbolConstructor;
+ }
// Initialized when dart:mirrors is loaded.
ClassElement mirrorSystemClass;
@@ -191,13 +196,6 @@
// Initialized after mirrorSystemClass has been resolved.
FunctionElement mirrorSystemGetNameFunction;
- // Initialized when dart:_internal is loaded.
- ClassElement symbolImplementationClass;
-
- // Initialized when symbolImplementationClass has been resolved.
- // TODO(johnniwinther): Move this to [BackendHelpers].
- FunctionElement symbolValidatedConstructor;
-
// Initialized when mirrorsUsedClass has been resolved.
FunctionElement mirrorsUsedConstructor;
@@ -219,8 +217,11 @@
/// The [String.fromEnvironment] constructor.
ConstructorElement stringEnvironment;
+ // TODO(zarah): Remove this map and incorporate compile-time errors
+ // in the model.
/// Tracks elements with compile-time errors.
- final Set<Element> elementsWithCompileTimeErrors = new Set<Element>();
+ final Map<Element, List<DiagnosticMessage>> elementsWithCompileTimeErrors =
+ new Map<Element, List<DiagnosticMessage>>();
final Environment environment;
// TODO(sigmund): delete once we migrate the rest of the compiler to use
@@ -245,6 +246,8 @@
GenericTask reuseLibraryTask;
+ GenericTask selfTask;
+
/// The constant environment for the frontend interpretation of compile-time
/// constants.
ConstantEnvironment constants;
@@ -257,9 +260,6 @@
/// A customizable filter that is applied to enqueued work items.
QueueFilter enqueuerFilter = new QueueFilter();
- final Selector symbolValidatedConstructorSelector =
- new Selector.call(const PublicName('validated'), CallStructure.ONE_ARG);
-
static const String CREATE_INVOCATION_MIRROR = 'createInvocationMirror';
bool enabledRuntimeType = false;
@@ -281,32 +281,28 @@
static const int PHASE_COMPILING = 3;
int phase;
- bool compilationFailedInternal = false;
-
- bool get compilationFailed => compilationFailedInternal;
-
- void set compilationFailed(bool value) {
- if (value) {
- elementsWithCompileTimeErrors.add(currentElement);
- }
- compilationFailedInternal = value;
- }
+ bool compilationFailed = false;
Compiler(
{CompilerOptions options,
api.CompilerOutput outputProvider,
- this.environment: const _EmptyEnvironment()})
+ this.environment: const _EmptyEnvironment(),
+ MakeBackendFuncion makeBackend,
+ MakeReporterFunction makeReporter})
: this.options = options,
this.cacheStrategy = new CacheStrategy(options.hasIncrementalSupport),
this.userOutputProvider = outputProvider == null
? const NullCompilerOutput()
: outputProvider {
world = new World(this);
+ if (makeReporter != null) {
+ _reporter = makeReporter(this, options);
+ } else {
+ _reporter = new CompilerDiagnosticReporter(this, options);
+ }
+ _resolution = new _CompilerResolution(this);
// TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
// make its field final.
- _reporter = new _CompilerDiagnosticReporter(this, options);
- _parsing = new _CompilerParsing(this);
- _resolution = new _CompilerResolution(this);
_coreTypes = new _CompilerCoreTypes(_resolution);
types = new Types(_resolution);
tracer = new Tracer(this, this.outputProvider);
@@ -319,7 +315,9 @@
// for global dependencies.
globalDependencies = new GlobalDependencyRegistry(this);
- if (options.emitJavaScript) {
+ if (makeBackend != null) {
+ backend = makeBackend(this);
+ } else if (options.emitJavaScript) {
js_backend.JavaScriptBackend jsBackend = new js_backend.JavaScriptBackend(
this,
generateSourceMap: options.generateSourceMap,
@@ -340,19 +338,20 @@
}
tasks = [
- dietParser = new DietParserTask(this, parsing.parserOptions, idGenerator),
+ dietParser =
+ new DietParserTask(this, options, idGenerator, backend, reporter),
scanner = createScannerTask(),
serialization = new SerializationTask(this),
libraryLoader = new LibraryLoaderTask(
this,
- new _ResolvedUriTranslator(this),
+ this.resolvedUriTranslator,
new _ScriptLoader(this),
new _ElementScanner(scanner),
this.serialization,
this,
environment),
- parser = new ParserTask(this, parsing.parserOptions),
- patchParser = new PatchParserTask(this, parsing.parserOptions),
+ parser = new ParserTask(this, options),
+ patchParser = new PatchParserTask(this, options),
resolver = createResolverTask(),
closureToClassMapper = new closureMapping.ClosureTask(this),
checker = new TypeCheckerTask(this),
@@ -360,11 +359,15 @@
constants = backend.constantCompilerTask,
deferredLoadTask = new DeferredLoadTask(this),
mirrorUsageAnalyzerTask = new MirrorUsageAnalyzerTask(this),
- enqueuer = new EnqueueTask(this),
+ enqueuer = backend.makeEnqueuer(),
dumpInfoTask = new DumpInfoTask(this),
reuseLibraryTask = new GenericTask('Reuse library', this),
+ selfTask = new GenericTask('self', this),
];
+ _parsingContext =
+ new ParsingContext(reporter, options, parser, patchParser, backend);
+
tasks.addAll(backend.tasks);
}
@@ -391,10 +394,6 @@
bool get disableTypeInference =>
options.disableTypeInference || compilationFailed;
- // TODO(het): remove this and pass idGenerator directly instead
- @deprecated
- int getNextFreeId() => idGenerator.getNextFreeId();
-
void unimplemented(Spannable spannable, String methodName) {
reporter.internalError(spannable, "$methodName not implemented.");
}
@@ -402,19 +401,19 @@
// Compiles the dart script at [uri].
//
// The resulting future will complete with true if the compilation
- // succeded.
- Future<bool> run(Uri uri) {
- totalCompileTime.start();
+ // succeeded.
+ Future<bool> run(Uri uri) => selfTask.measureSubtask("Compiler.run", () {
+ measurer.startWallClock();
return new Future.sync(() => runInternal(uri))
.catchError((error) => _reporter.onError(uri, error))
.whenComplete(() {
tracer.close();
- totalCompileTime.stop();
+ measurer.stopWallClock();
}).then((_) {
return !compilationFailed;
});
- }
+ });
/// This method is called immediately after the [LibraryElement] [library] has
/// been created.
@@ -448,8 +447,6 @@
if (uri == Uris.dart_core) {
initializeCoreClasses();
identicalFunction = coreLibrary.find('identical');
- } else if (uri == Uris.dart__internal) {
- symbolImplementationClass = findRequiredElement(library, 'Symbol');
} else if (uri == Uris.dart_mirrors) {
mirrorSystemClass = findRequiredElement(library, 'MirrorSystem');
mirrorsUsedClass = findRequiredElement(library, 'MirrorsUsed');
@@ -524,13 +521,6 @@
return importChains;
}
- /// Register that [uri] was recognized but disallowed as a dependency.
- ///
- /// For instance import of 'dart:io' without '--categories=Server'.
- void registerDisallowedLibraryUse(Uri uri) {
- disallowedLibraryUris.add(uri);
- }
-
/// This method is called when all new libraries loaded through
/// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
/// have been computed.
@@ -541,7 +531,7 @@
/// libraries.
Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
return new Future.sync(() {
- for (Uri uri in disallowedLibraryUris) {
+ for (Uri uri in resolvedUriTranslator.disallowedLibraryUris) {
if (loadedLibraries.containsLibrary(uri)) {
Set<String> importChains =
computeImportChainsFor(loadedLibraries, uri);
@@ -618,14 +608,11 @@
// [JavaScriptBackend]. Currently needed for testing.
String get patchVersion => backend.patchVersion;
+ // TODO(johnniwinther): Remove this. All elements should be looked up on
+ // demand.
void onClassResolved(ClassElement cls) {
if (mirrorSystemClass == cls) {
mirrorSystemGetNameFunction = cls.lookupLocalMember('getName');
- } else if (coreClasses.symbolClass == cls) {
- symbolConstructor = cls.constructors.head;
- } else if (symbolImplementationClass == cls) {
- symbolValidatedConstructor =
- cls.lookupConstructor(symbolValidatedConstructorSelector.name);
} else if (mirrorsUsedClass == cls) {
mirrorsUsedConstructor = cls.constructors.head;
} else if (coreClasses.intClass == cls) {
@@ -813,7 +800,9 @@
}
/// Performs the compilation when all libraries have been loaded.
- void compileLoadedLibraries() {
+ void compileLoadedLibraries()
+ => selfTask.measureSubtask("Compiler.compileLoadedLibraries", () {
+
computeMain();
mirrorUsageAnalyzerTask.analyzeUsage(mainApp);
@@ -916,7 +905,7 @@
backend.sourceInformationStrategy.onComplete();
checkQueues();
- }
+ });
void fullyEnqueueLibrary(LibraryElement library, Enqueuer world) {
void enqueueAll(Element element) {
@@ -952,15 +941,20 @@
/**
* Empty the [world] queue.
*/
- void emptyQueue(Enqueuer world) {
+ void emptyQueue(Enqueuer world)
+ => selfTask.measureSubtask("Compiler.emptyQueue", () {
world.forEach((WorkItem work) {
- reporter.withCurrentElement(work.element, () {
- world.applyImpact(work.element, work.run(this, world));
- });
+ reporter.withCurrentElement(
+ work.element, () => selfTask.measureSubtask("world.applyImpact", () {
+ world.applyImpact(
+ work.element,
+ selfTask.measureSubtask("work.run", () => work.run(this, world)));
+ }));
});
- }
+ });
- void processQueue(Enqueuer world, Element main) {
+ void processQueue(Enqueuer world, Element main)
+ => selfTask.measureSubtask("Compiler.processQueue", () {
world.nativeEnqueuer.processNativeClasses(libraryLoader.libraries);
if (main != null && !main.isMalformed) {
FunctionElement mainMethod = main;
@@ -988,7 +982,7 @@
impactStrategy.onImpactUsed(world.impactUse);
backend.onQueueClosed();
assert(compilationFailed || world.checkNoEnqueuedInvokedInstanceMethods());
- }
+ });
/**
* Perform various checks of the queues. This includes checking that
@@ -1029,7 +1023,8 @@
}
}
- WorldImpact analyzeElement(Element element) {
+ WorldImpact analyzeElement(Element element)
+ => selfTask.measureSubtask("Compiler.analyzeElement", () {
assert(invariant(
element,
element.impliesType ||
@@ -1043,9 +1038,11 @@
message: 'Element $element is not analyzable.'));
assert(invariant(element, element.isDeclaration));
return resolution.computeWorldImpact(element);
- }
+ });
- WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
+ WorldImpact analyze(ResolutionWorkItem work,
+ ResolutionEnqueuer world)
+ => selfTask.measureSubtask("Compiler.analyze", () {
assert(invariant(work.element, identical(world, enqueuer.resolution)));
assert(invariant(work.element, !work.isAnalyzed,
message: 'Element ${work.element} has already been analyzed'));
@@ -1063,10 +1060,10 @@
return const WorldImpact();
}
WorldImpact worldImpact = analyzeElement(element);
- backend.onElementResolved(element, element.resolvedAst.elements);
+ backend.onElementResolved(element);
world.registerProcessedElement(element);
return worldImpact;
- }
+ });
WorldImpact codegen(CodegenWorkItem work, CodegenEnqueuer world) {
assert(invariant(work.element, identical(world, enqueuer.codegen)));
@@ -1084,7 +1081,7 @@
List<DiagnosticMessage> infos, api.Diagnostic kind);
void reportCrashInUserCode(String message, exception, stackTrace) {
- _reporter.onCrashInUserCode(message, exception, stackTrace);
+ reporter.onCrashInUserCode(message, exception, stackTrace);
}
/// Messages for which compile-time errors are reported but compilation
@@ -1110,26 +1107,7 @@
if (markCompilationAsFailed(message, kind)) {
compilationFailed = true;
}
- }
-
- // TODO(sigmund): move this dart doc somewhere else too.
- /**
- * Translates the [resolvedUri] into a readable URI.
- *
- * The [importingLibrary] holds the library importing [resolvedUri] or
- * [:null:] if [resolvedUri] is loaded as the main library. The
- * [importingLibrary] is used to grant access to internal libraries from
- * platform libraries and patch libraries.
- *
- * If the [resolvedUri] is not accessible from [importingLibrary], this method
- * is responsible for reporting errors.
- *
- * See [LibraryLoader] for terminology on URIs.
- */
- Uri translateResolvedUri(
- LibraryElement importingLibrary, Uri resolvedUri, Spannable spannable) {
- unimplemented(importingLibrary, 'Compiler.translateResolvedUri');
- return null;
+ registerCompiletimeError(currentElement, message);
}
/**
@@ -1255,6 +1233,7 @@
}
void forgetElement(Element element) {
+ resolution.forgetElement(element);
enqueuer.forgetElement(element);
if (element is MemberElement) {
for (Element closure in element.nestedClosures) {
@@ -1265,8 +1244,24 @@
backend.forgetElement(element);
}
+ /// Returns [true] if a compile-time error has been reported for element.
bool elementHasCompileTimeError(Element element) {
- return elementsWithCompileTimeErrors.contains(element);
+ return elementsWithCompileTimeErrors.containsKey(element);
+ }
+
+ /// Associate [element] with a compile-time error [message].
+ void registerCompiletimeError(Element element, DiagnosticMessage message) {
+ // The information is only needed if [generateCodeWithCompileTimeErrors].
+ if (options.generateCodeWithCompileTimeErrors) {
+ if (element == null) {
+ // Record as global error.
+ // TODO(zarah): Extend element model to represent compile-time
+ // errors instead of using a map.
+ element = mainFunction;
+ }
+ elementsWithCompileTimeErrors.
+ putIfAbsent(element, () => <DiagnosticMessage>[]).add(message);
+ }
}
EventSink<String> outputProvider(String name, String extension) {
@@ -1438,7 +1433,7 @@
}
}
-class _CompilerDiagnosticReporter extends DiagnosticReporter {
+class CompilerDiagnosticReporter extends DiagnosticReporter {
final Compiler compiler;
final DiagnosticOptions options;
@@ -1453,7 +1448,7 @@
/// suppressed for each library.
Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
- _CompilerDiagnosticReporter(this.compiler, this.options);
+ CompilerDiagnosticReporter(this.compiler, this.options);
Element get currentElement => _currentElement;
@@ -1529,6 +1524,13 @@
if (kind == api.Diagnostic.ERROR ||
kind == api.Diagnostic.CRASH ||
(options.fatalWarnings && kind == api.Diagnostic.WARNING)) {
+ Element errorElement;
+ if (message.spannable is Element) {
+ errorElement = message.spannable;
+ } else {
+ errorElement = currentElement;
+ }
+ compiler.registerCompiletimeError(errorElement, message);
compiler.fatalDiagnosticReported(message, infos, kind);
}
}
@@ -1818,6 +1820,7 @@
throw error;
}
+ @override
void onCrashInUserCode(String message, exception, stackTrace) {
hasCrashed = true;
print('$message: ${tryToString(exception)}');
@@ -1858,7 +1861,7 @@
DiagnosticReporter get reporter => compiler.reporter;
@override
- Parsing get parsing => compiler.parsing;
+ ParsingContext get parsingContext => compiler.parsingContext;
@override
CoreTypes get coreTypes => compiler.coreTypes;
@@ -1894,7 +1897,20 @@
}
@override
+ void ensureResolved(Element element) {
+ if (compiler.serialization.isDeserialized(element)) {
+ return;
+ }
+ computeWorldImpact(element);
+ }
+
+ @override
bool hasResolvedAst(Element element) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
+ if (compiler.serialization.isDeserialized(element)) {
+ return compiler.serialization.hasResolvedAst(element);
+ }
return element is AstElement &&
hasBeenResolved(element) &&
element.hasResolvedAst;
@@ -1902,7 +1918,12 @@
@override
ResolvedAst getResolvedAst(Element element) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
if (hasResolvedAst(element)) {
+ if (compiler.serialization.isDeserialized(element)) {
+ return compiler.serialization.getResolvedAst(element);
+ }
AstElement astElement = element;
return astElement.resolvedAst;
}
@@ -1911,15 +1932,32 @@
return null;
}
+ @override
+ ResolvedAst computeResolvedAst(Element element) {
+ ensureResolved(element);
+ return getResolvedAst(element);
+ }
@override
bool hasResolutionImpact(Element element) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
+ if (compiler.serialization.isDeserialized(element)) {
+ return compiler.serialization.hasResolutionImpact(element);
+ }
return _resolutionImpactCache.containsKey(element);
}
@override
ResolutionImpact getResolutionImpact(Element element) {
- ResolutionImpact resolutionImpact = _resolutionImpactCache[element];
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
+ ResolutionImpact resolutionImpact;
+ if (compiler.serialization.isDeserialized(element)) {
+ resolutionImpact = compiler.serialization.getResolutionImpact(element);
+ } else {
+ resolutionImpact = _resolutionImpactCache[element];
+ }
assert(invariant(element, resolutionImpact != null,
message: "ResolutionImpact not available for $element."));
return resolutionImpact;
@@ -1927,6 +1965,8 @@
@override
WorldImpact getWorldImpact(Element element) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
WorldImpact worldImpact = _worldImpactCache[element];
assert(invariant(element, worldImpact != null,
message: "WorldImpact not computed for $element."));
@@ -1935,11 +1975,14 @@
@override
WorldImpact computeWorldImpact(Element element) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
return _worldImpactCache.putIfAbsent(element, () {
assert(compiler.parser != null);
Node tree = compiler.parser.parse(element);
assert(invariant(element, !element.isSynthesized || tree == null));
ResolutionImpact resolutionImpact = compiler.resolver.resolve(element);
+
if (compiler.serialization.supportSerialization ||
retainCachesForTesting) {
// [ResolutionImpact] is currently only used by serialization. The
@@ -1963,6 +2006,8 @@
@override
void uncacheWorldImpact(Element element) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration."));
if (retainCachesForTesting) return;
if (compiler.serialization.isDeserialized(element)) return;
assert(invariant(element, _worldImpactCache[element] != null,
@@ -1995,34 +2040,12 @@
return new ResolutionWorkItem(element, compilationContext);
}
}
-}
-
-// TODO(johnniwinther): Move [ParserTask], [PatchParserTask], [DietParserTask]
-// and [ScannerTask] here.
-class _CompilerParsing implements Parsing {
- final Compiler compiler;
-
- _CompilerParsing(this.compiler);
@override
- DiagnosticReporter get reporter => compiler.reporter;
-
- @override
- measure(f()) => compiler.parser.measure(f);
-
- @override
- void parsePatchClass(ClassElement cls) {
- compiler.patchParser.measure(() {
- if (cls.isPatch) {
- compiler.patchParser.parsePatchClassNode(cls);
- }
- });
+ void forgetElement(Element element) {
+ _worldImpactCache.remove(element);
+ _resolutionImpactCache.remove(element);
}
-
- ScannerOptions getScannerOptionsFor(Element element) =>
- new ScannerOptions.from(compiler, element.library);
-
- ParserOptions get parserOptions => compiler.options;
}
class GlobalDependencyRegistry extends EagerRegistry {
@@ -2049,17 +2072,6 @@
}
}
-// TODO(sigmund): in the future, each of these classes should be self contained
-// and not use references to `compiler`.
-class _ResolvedUriTranslator implements ResolvedUriTranslator {
- Compiler compiler;
- _ResolvedUriTranslator(this.compiler);
-
- Uri translate(LibraryElement importingLibrary, Uri resolvedUri,
- [Spannable spannable]) =>
- compiler.translateResolvedUri(importingLibrary, resolvedUri, spannable);
-}
-
class _ScriptLoader implements ScriptLoader {
Compiler compiler;
_ScriptLoader(this.compiler);
diff --git a/pkg/compiler/lib/src/constants/constructors.dart b/pkg/compiler/lib/src/constants/constructors.dart
index c2b53fc..b8e7471 100644
--- a/pkg/compiler/lib/src/constants/constructors.dart
+++ b/pkg/compiler/lib/src/constants/constructors.dart
@@ -5,7 +5,7 @@
library dart2js.constants.constructors;
import '../dart_types.dart';
-import '../elements/elements.dart' show ConstructorElement, FieldElement;
+import '../elements/elements.dart' show FieldElement;
import '../universe/call_structure.dart' show CallStructure;
import '../util/util.dart';
import 'evaluation.dart';
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index 809d7e0..d476dd6b 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -11,7 +11,6 @@
import '../elements/elements.dart'
show
ConstructorElement,
- Element,
FieldElement,
FunctionElement,
PrefixElement,
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 1cc0271..40bda63 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -8,7 +8,7 @@
import '../core_types.dart';
import '../dart_types.dart';
import '../elements/elements.dart'
- show ClassElement, Element, FieldElement, FunctionElement, PrefixElement;
+ show FieldElement, FunctionElement, PrefixElement;
import '../tree/tree.dart' hide unparse;
import '../util/util.dart' show Hashing;
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 7927ba0..dd756c6 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -6,10 +6,10 @@
import '../closure.dart' as closure;
import '../common.dart';
-import '../common/names.dart' show Names, Selectors;
+import '../common/names.dart' show Selectors;
import '../compile_time_constants.dart' show BackendConstantEnvironment;
import '../constants/constant_system.dart';
-import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
+import '../constants/values.dart' show ConstantValue;
import '../dart_types.dart';
import '../elements/elements.dart';
import '../io/source_information.dart';
@@ -27,7 +27,6 @@
import '../types/types.dart' show TypeMask;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector, SelectorKind;
-
import 'cps_ir_builder_task.dart' show GlobalProgramInformation;
import 'cps_ir_nodes.dart' as ir;
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 e9d1845..bc77a98 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
@@ -4,44 +4,39 @@
library dart2js.ir_builder_task;
+import 'package:js_runtime/shared/embedded_names.dart'
+ show JsBuiltin, JsGetName;
+
import '../closure.dart' as closure;
import '../common.dart';
import '../common/names.dart' show Identifiers, Names, Selectors;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../constants/expressions.dart';
+import '../constants/values.dart' show ConstantValue;
+import '../constants/values.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
-import '../elements/modelx.dart'
- show
- SynthesizedConstructorElementX,
- ConstructorBodyElementX,
- FunctionSignatureX;
+import '../elements/modelx.dart' show ConstructorBodyElementX;
import '../io/source_information.dart';
+import '../js/js.dart' as js show js, Template, Expression, Name;
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart'
show JavaScriptBackend, SyntheticConstantKind;
-import '../resolution/tree_elements.dart' show TreeElements;
-import '../resolution/semantic_visitor.dart';
+import '../native/native.dart' show NativeBehavior, HasCapturedPlaceholders;
import '../resolution/operators.dart' as op;
+import '../resolution/semantic_visitor.dart';
+import '../resolution/tree_elements.dart' show TreeElements;
+import '../ssa/types.dart' show TypeMaskFactory;
import '../tree/tree.dart' as ast;
import '../types/types.dart' show TypeMask;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
-import '../constants/values.dart' show ConstantValue;
-import 'cps_ir_nodes.dart' as ir;
-import 'cps_ir_builder.dart';
-import '../native/native.dart' show NativeBehavior, HasCapturedPlaceholders;
-
-// TODO(karlklose): remove.
-import '../js/js.dart' as js show js, Template, Expression, Name;
-import '../ssa/types.dart' show TypeMaskFactory;
import '../util/util.dart';
-
-import 'package:js_runtime/shared/embedded_names.dart'
- show JsBuiltin, JsGetName;
-import '../constants/values.dart';
+import 'cps_ir_builder.dart';
+import 'cps_ir_nodes.dart' as ir;
import 'type_mask_system.dart' show TypeMaskSystem;
+// TODO(karlklose): remove.
typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode);
@@ -79,14 +74,14 @@
return measure(() {
bailoutMessage = null;
- TreeElements elementsMapping = element.resolvedAst.elements;
+ ResolvedAst resolvedAst = element.resolvedAst;
element = element.implementation;
return reporter.withCurrentElement(element, () {
SourceInformationBuilder sourceInformationBuilder =
sourceInformationStrategy.createBuilderForContext(element);
- IrBuilderVisitor builder = new IrBuilderVisitor(elementsMapping,
- compiler, sourceInformationBuilder, typeMaskSystem);
+ IrBuilderVisitor builder = new IrBuilderVisitor(
+ resolvedAst, compiler, sourceInformationBuilder, typeMaskSystem);
ir.FunctionDefinition irNode = builder.buildExecutable(element);
if (irNode == null) {
bailoutMessage = builder.bailoutMessage;
@@ -123,7 +118,7 @@
BaseImplementationOfIndexCompoundsMixin<ir.Primitive, dynamic>,
BaseImplementationOfSuperIndexSetIfNullMixin<ir.Primitive, dynamic>
implements SemanticSendVisitor<ir.Primitive, dynamic> {
- final TreeElements elements;
+ final ResolvedAst resolvedAst;
final Compiler compiler;
final SourceInformationBuilder sourceInformationBuilder;
final TypeMaskSystem typeMaskSystem;
@@ -155,8 +150,10 @@
// arguments, and what the arguments are.
/// Construct a top-level visitor.
- IrBuilderVisitor(this.elements, this.compiler, this.sourceInformationBuilder,
- this.typeMaskSystem);
+ IrBuilderVisitor(this.resolvedAst, this.compiler,
+ this.sourceInformationBuilder, this.typeMaskSystem);
+
+ TreeElements get elements => resolvedAst.elements;
JavaScriptBackend get backend => compiler.backend;
BackendHelpers get helpers => backend.helpers;
@@ -193,7 +190,7 @@
/// one currently being built.
ClosureScope getClosureScopeForFunction(FunctionElement function) {
closure.ClosureClassMap map = compiler.closureToClassMapper
- .computeClosureToClassMapping(function, function.node, elements);
+ .computeClosureToClassMapping(function.resolvedAst);
return new ClosureScope(map.capturingScopes[function.node]);
}
@@ -505,7 +502,7 @@
/// Every visitor can only be applied to nodes in one context, because
/// the [elements] field is specific to that context.
IrBuilderVisitor makeVisitorForContext(AstElement context) {
- return new IrBuilderVisitor(context.resolvedAst.elements, compiler,
+ return new IrBuilderVisitor(context.resolvedAst, compiler,
sourceInformationBuilder.forContext(context), typeMaskSystem);
}
@@ -545,7 +542,7 @@
void loadArguments(ConstructorElement target, CallStructure call,
List<ir.Primitive> arguments) {
assert(target.isImplementation);
- assert(target == elements.analyzedElement);
+ assert(target.declaration == resolvedAst.element);
FunctionSignature signature = target.functionSignature;
// Establish a scope in case parameters are captured.
@@ -620,7 +617,7 @@
List<ConstructorElement> supers,
Map<FieldElement, ir.Primitive> fieldValues) {
assert(constructor.isImplementation);
- assert(constructor == elements.analyzedElement);
+ assert(constructor.declaration == resolvedAst.element);
ClassElement enclosingClass = constructor.enclosingClass.implementation;
// Evaluate declaration-site field initializers, unless this constructor
// redirects to another using a `this()` initializer. In that case, these
@@ -714,7 +711,7 @@
ConstructorElement constructor = body.constructor;
ast.FunctionExpression node = constructor.node;
closureClassMap = compiler.closureToClassMapper
- .computeClosureToClassMapping(constructor, node, elements);
+ .computeClosureToClassMapping(constructor.resolvedAst);
// We compute variables boxed in mutable variables on entry to each try
// block, not including variables captured by a closure (which are boxed
@@ -745,7 +742,7 @@
assert(elements[node] != null);
closureClassMap = compiler.closureToClassMapper
- .computeClosureToClassMapping(element, node, elements);
+ .computeClosureToClassMapping(element.resolvedAst);
TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
tryStatements = variables.tryStatements;
IrBuilder builder = getBuilderFor(element);
@@ -758,7 +755,7 @@
return null; // Nothing to do.
}
closureClassMap = compiler.closureToClassMapper
- .computeClosureToClassMapping(element, element.node, elements);
+ .computeClosureToClassMapping(element.resolvedAst);
IrBuilder builder = getBuilderFor(element);
return withBuilder(builder, () {
irBuilder.buildFunctionHeader(<Local>[]);
@@ -908,7 +905,6 @@
//
assert(parameters.length == 1 || parameters.length == 2);
ir.Primitive allocation = irBuilder.buildLocalGet(parameters[0]);
- ClassElement classElement = element.enclosingElement;
// Only call setRuntimeTypeInfo if JSArray requires the type parameter.
if (requiresRuntimeTypes) {
@@ -1130,7 +1126,7 @@
<ir.Primitive>[stream, dummyTypeArgument],
sourceInformationBuilder.buildGeneric(node)));
- ir.Node buildTryBody(IrBuilder builder) {
+ buildTryBody(IrBuilder builder) {
ir.Node buildLoopCondition(IrBuilder builder) {
ir.Primitive moveNext = builder.buildDynamicInvocation(
iterator,
@@ -2271,7 +2267,7 @@
// libraries contain a dummy const constructor implementation that
// doesn't perform validation and the compiler compiles a call to
// (non-const) Symbol.validated when it sees new Symbol(...).
- target = compiler.symbolValidatedConstructor;
+ target = helpers.symbolValidatedConstructor;
} else {
target = constructor.implementation;
}
@@ -3201,8 +3197,7 @@
}
Link<ast.Node> argumentNodes = argumentList.nodes;
- NativeBehavior behavior =
- compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ NativeBehavior behavior = elements.getNativeData(node);
switch (function.name) {
case 'JS':
validateArgumentCount(minimum: 2);
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 3e82f93..7ba13c8 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -2098,10 +2098,6 @@
// UTILITY STUFF
// ----------------------------------------------------------------------------
-Reference<Primitive> _reference(Primitive definition) {
- return new Reference<Primitive>(definition);
-}
-
Reference<Primitive> _optionalReference(Primitive definition) {
return definition == null ? null : new Reference<Primitive>(definition);
}
diff --git a/pkg/compiler/lib/src/cps_ir/inline.dart b/pkg/compiler/lib/src/cps_ir/inline.dart
index cbb673d..9454e38 100644
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ b/pkg/compiler/lib/src/cps_ir/inline.dart
@@ -4,21 +4,21 @@
library cps_ir.optimization.inline;
+import 'package:js_ast/js_ast.dart' as js;
+
+import '../dart_types.dart' show DartType, GenericType;
+import '../elements/elements.dart';
+import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/types.dart' show TypeMask;
+import '../universe/call_structure.dart' show CallStructure;
+import '../universe/selector.dart' show Selector;
+import '../world.dart' show World;
import 'cps_fragment.dart';
import 'cps_ir_builder.dart' show ThisParameterLocal;
import 'cps_ir_nodes.dart';
import 'optimizers.dart';
import 'type_mask_system.dart' show TypeMaskSystem;
-import '../dart_types.dart' show DartType, GenericType;
-import '../world.dart' show World;
-import '../elements/elements.dart';
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
-import '../types/types.dart'
- show FlatTypeMask, ForwardingTypeMask, TypeMask, UnionTypeMask;
-import '../universe/call_structure.dart' show CallStructure;
-import '../universe/selector.dart' show Selector;
-import 'package:js_ast/js_ast.dart' as js;
/// Inlining stack entries.
///
@@ -211,7 +211,8 @@
// Do not inline in functions containing try statements. V8 does not
// optimize code in such functions, so inlining will move optimizable code
// into a context where it cannot be optimized.
- if (function.resolvedAst.elements.containsTryStatement) {
+ if (function.resolvedAst.kind == ResolvedAstKind.PARSED &&
+ function.resolvedAst.elements.containsTryStatement) {
return;
}
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index c77bd02..a2bb010 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -4,7 +4,8 @@
library dart2js.type_mask_system;
-import '../common/names.dart' show Selectors, Identifiers;
+import '../closure.dart' show ClosureFieldElement, BoxLocal, TypeVariableLocal;
+import '../common/names.dart' show Identifiers;
import '../compiler.dart' as dart2js show Compiler;
import '../constants/values.dart';
import '../dart_types.dart' as types;
@@ -12,11 +13,10 @@
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart' show JavaScriptBackend;
import '../types/abstract_value_domain.dart';
-import '../types/types.dart';
import '../types/constants.dart' show computeTypeMask;
+import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show World;
-import '../closure.dart' show ClosureFieldElement, BoxLocal, TypeVariableLocal;
class TypeMaskSystem implements AbstractValueDomain {
final TypesTask inferrer;
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 0518e488..336dfc6 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -4,28 +4,20 @@
library dart2js.cmdline;
-import 'dart:async' show Future, EventSink;
+import 'dart:async' show Future;
import 'dart:convert' show UTF8, LineSplitter;
-import 'dart:io'
- show
- exit,
- File,
- FileMode,
- Platform,
- RandomAccessFile,
- FileSystemException,
- stdin,
- stderr;
+import 'dart:io' show exit, File, FileMode, Platform, stdin, stderr;
+
+import 'package:package_config/discovery.dart' show findPackages;
import '../compiler.dart' as api;
import 'commandline_options.dart';
+import 'filenames.dart';
import 'io/source_file.dart';
import 'source_file_provider.dart';
-import 'filenames.dart';
+import 'util/command_line.dart';
import 'util/uri_extras.dart';
import 'util/util.dart' show stackTraceFilePrefix;
-import 'util/command_line.dart';
-import 'package:package_config/discovery.dart' show findPackages;
const String LIBRARY_ROOT = '../../../../../sdk';
const String OUTPUT_LANGUAGE_DART = 'Dart';
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index 8d9d0cc..3501182 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -236,7 +236,7 @@
if (useMirrorHelperLibrary &&
loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
return compiler.libraryLoader
- .loadLibrary(compiler.translateResolvedUri(
+ .loadLibrary(compiler.resolvedUriTranslator.translate(
loadedLibraries.getLibrary(Uris.dart_mirrors),
MirrorRenamerImpl.DART_MIRROR_HELPER,
null))
@@ -317,7 +317,6 @@
superclass.forEachLocalMember((MemberElement element) {
if (element.isConstructor || element.isStatic) return;
- FunctionElement function = element.asFunctionElement();
element.computeType(resolution);
Selector selector = new Selector.fromElement(element);
registerUse(new DynamicUse(selector, null));
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
index 1ab7882..81eae70 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
@@ -1106,7 +1106,7 @@
bound =
makeType(TypeGenerator.createType(typeVariable.element.bound));
}
- tree.TypeVariable node = new tree.TypeVariable(id, bound);
+ tree.TypeVariable node = new tree.TypeVariable(id, extendsToken, bound);
treeElements.setType(node, typeVariable);
typeVariableList.add(node);
}
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 41ce1e5..685077d 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -6,12 +6,11 @@
import 'dart:math' show min;
-import 'common.dart';
import 'common/resolution.dart' show Resolution;
+import 'common.dart';
import 'core_types.dart';
-import 'elements/modelx.dart'
- show LibraryElementX, TypeDeclarationElementX, TypedefElementX;
import 'elements/elements.dart';
+import 'elements/modelx.dart' show TypeDeclarationElementX;
import 'ordered_typeset.dart' show OrderedTypeSet;
import 'util/util.dart' show equalElements;
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 0d377aa..5ce0d30 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -4,9 +4,9 @@
library deferred_load;
-import 'common.dart';
import 'common/backend_api.dart' show Backend;
import 'common/tasks.dart' show CompilerTask;
+import 'common.dart';
import 'compiler.dart' show Compiler;
import 'constants/values.dart'
show
@@ -21,31 +21,21 @@
AstElement,
ClassElement,
Element,
- ElementKind,
Elements,
ExportElement,
FunctionElement,
ImportElement,
LibraryElement,
- LocalFunctionElement,
MetadataAnnotation,
PrefixElement,
- ScopeContainerElement,
+ ResolvedAstKind,
TypedefElement;
import 'js_backend/js_backend.dart' show JavaScriptBackend;
import 'resolution/resolution.dart' show AnalyzableElementX;
import 'resolution/tree_elements.dart' show TreeElements;
import 'tree/tree.dart' as ast;
-import 'tree/tree.dart'
- show
- Import,
- LibraryTag,
- LibraryDependency,
- LiteralDartString,
- LiteralString,
- NewExpression,
- Node;
-import 'universe/use.dart' show DynamicUse, StaticUse, TypeUse, TypeUseKind;
+import 'tree/tree.dart' show Import, Node;
+import 'universe/use.dart' show StaticUse, TypeUse, TypeUseKind;
import 'universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
import 'util/setlet.dart' show Setlet;
@@ -337,6 +327,10 @@
}),
IMPACT_USE);
+ if (analyzableElement.resolvedAst.kind != ResolvedAstKind.PARSED) {
+ return;
+ }
+
TreeElements treeElements = analyzableElement.resolvedAst.elements;
assert(treeElements != null);
diff --git a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
index 3cb959f..e31edde 100644
--- a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
+++ b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
@@ -60,6 +60,10 @@
DiagnosticMessage createMessage(Spannable spannable, MessageKind messageKind,
[Map arguments = const {}]);
+
+ /// Called when an [exception] is thrown from user-provided code, like from
+ /// the input provider or diagnostics handler.
+ void onCrashInUserCode(String message, exception, stackTrace) {}
}
class DiagnosticMessage {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 726d914..854feb1 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -5,21 +5,21 @@
library dump_info;
import 'dart:convert'
- show ChunkedConversionSink, HtmlEscape, JsonEncoder, StringConversionSink;
+ show ChunkedConversionSink, JsonEncoder, StringConversionSink;
import 'package:dart2js_info/info.dart';
-import 'common.dart';
import 'common/tasks.dart' show CompilerTask;
-import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
+import 'common.dart';
import 'compiler.dart' show Compiler;
+import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
import 'deferred_load.dart' show OutputUnit;
import 'elements/elements.dart';
import 'elements/visitor.dart';
import 'info/send_info.dart' show collectSendMeasurements;
+import 'js/js.dart' as jsAst;
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 'types/types.dart' show TypeMask;
import 'universe/universe.dart' show ReceiverConstraint;
import 'universe/world_impact.dart'
@@ -579,7 +579,7 @@
dart2jsVersion:
compiler.options.hasBuildId ? compiler.options.buildId : null,
compilationMoment: new DateTime.now(),
- compilationDuration: compiler.totalCompileTime.elapsed,
+ compilationDuration: compiler.measurer.wallClock.elapsed,
toJsonDuration: stopwatch.elapsedMilliseconds,
dumpInfoDuration: this.timing,
noSuchMethodEnabled: compiler.backend.enabledNoSuchMethod,
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart
index bbc682a..9cdce47 100644
--- a/pkg/compiler/lib/src/elements/common.dart
+++ b/pkg/compiler/lib/src/elements/common.dart
@@ -88,6 +88,13 @@
bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0;
@override
+ bool get isAssignable {
+ if (isFinal || isConst) return false;
+ if (isFunction || isConstructor) return false;
+ return true;
+ }
+
+ @override
Element get declaration => this;
@override
@@ -130,6 +137,20 @@
}
return cls;
}
+
+ @override
+ Element get outermostEnclosingMemberOrTopLevel {
+ // TODO(lrn): Why is this called "Outermost"?
+ // TODO(johnniwinther): Clean up this method: This method does not return
+ // the outermost for elements in closure classses, but some call-sites rely
+ // on that behavior.
+ for (Element e = this; e != null; e = e.enclosingElement) {
+ if (e.isClassMember || e.isTopLevel) {
+ return e;
+ }
+ }
+ return null;
+ }
}
abstract class LibraryElementCommon implements LibraryElement {
@@ -455,8 +476,6 @@
optionalParameters.forEach(function);
}
- Element get firstOptionalParameter => optionalParameters.first;
-
void forEachParameter(void function(Element parameter)) {
forEachRequiredParameter(function);
forEachOptionalParameter(function);
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 86a5f41..54ecf63 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -1106,7 +1106,6 @@
int get requiredParameterCount;
int get optionalParameterCount;
bool get optionalParametersAreNamed;
- FormalElement get firstOptionalParameter;
bool get hasOptionalParameters;
int get parameterCount;
@@ -1196,6 +1195,21 @@
String toString() {
return '${isAsync ? 'async' : 'sync'}${isYielding ? '*' : ''}';
}
+
+ /// Canonical list of marker values.
+ ///
+ /// Added to make [AsyncMarker] enum-like.
+ static const List<AsyncMarker> values = const <AsyncMarker>[
+ SYNC,
+ SYNC_STAR,
+ ASYNC,
+ ASYNC_STAR
+ ];
+
+ /// Index to this marker within [values].
+ ///
+ /// Added to make [AsyncMarker] enum-like.
+ int get index => values.indexOf(this);
}
/// A top level, static or instance function.
@@ -1626,14 +1640,86 @@
ResolvedAst get resolvedAst;
}
-class ResolvedAst {
+/// Enum values for different ways of defining semantics for an element.
+enum ResolvedAstKind {
+ /// The semantics of the element is defined in terms of an AST with resolved
+ /// data mapped in [TreeElements].
+ PARSED,
+
+ /// The element is an implicit default constructor. No AST or [TreeElements]
+ /// are provided.
+ DEFAULT_CONSTRUCTOR,
+
+ /// The element is an implicit forwarding constructor on a mixin application.
+ /// No AST or [TreeElements] are provided.
+ FORWARDING_CONSTRUCTOR,
+}
+
+/// [ResolvedAst] contains info that define the semantics of an element.
+abstract class ResolvedAst {
+ /// The element whose semantics is defined.
+ Element get element;
+
+ /// The kind of semantics definition used for this object.
+ ResolvedAstKind get kind;
+
+ /// The root AST node for the declaration of [element]. This only available if
+ /// [kind] is `ResolvedAstKind.PARSED`.
+ Node get node;
+
+ /// The AST node for the 'body' of [element].
+ ///
+ /// For functions and constructors this is the root AST node of the method
+ /// body, and for variables this is the root AST node of the initializer, if
+ /// available.
+ ///
+ /// This only available if [kind] is `ResolvedAstKind.PARSED`.
+ Node get body;
+
+ /// The [TreeElements] containing the resolution data for [node]. This only
+ /// available of [kind] is `ResolvedAstKind.PARSED`.
+ TreeElements get elements;
+}
+
+/// [ResolvedAst] implementation used for elements whose semantics is defined in
+/// terms an AST and a [TreeElements].
+class ParsedResolvedAst implements ResolvedAst {
final Element element;
final Node node;
+ final Node body;
final TreeElements elements;
- ResolvedAst(this.element, this.node, this.elements);
+ ParsedResolvedAst(this.element, this.node, this.body, this.elements);
- String toString() => '$element:$node';
+ ResolvedAstKind get kind => ResolvedAstKind.PARSED;
+
+ String toString() => '$kind:$element:$node';
+}
+
+/// [ResolvedAst] implementation used for synthesized elements whose semantics
+/// is not defined in terms an AST and a [TreeElements].
+class SynthesizedResolvedAst implements ResolvedAst {
+ final Element element;
+ final ResolvedAstKind kind;
+
+ SynthesizedResolvedAst(this.element, this.kind);
+
+ @override
+ TreeElements get elements {
+ throw new UnsupportedError('$this does not provide a TreeElements');
+ }
+
+ @override
+ Node get node {
+ throw new UnsupportedError('$this does not have a root AST node');
+ }
+
+ @override
+ Node get body {
+ throw new UnsupportedError('$this does not have a body AST node');
+ }
+
+ String toString() => '$kind:$element';
}
/// A [MemberSignature] is a member of an interface.
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index fe64aec..5a4cc108 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -5,7 +5,7 @@
library elements.modelx;
import '../common.dart';
-import '../common/resolution.dart' show Resolution, Parsing;
+import '../common/resolution.dart' show Resolution, ParsingContext;
import '../compiler.dart' show Compiler;
import '../constants/constant_constructors.dart';
import '../constants/constructors.dart';
@@ -52,7 +52,7 @@
Modifiers get modifiers => Modifiers.EMPTY;
- Node parseNode(Parsing parsing) {
+ Node parseNode(ParsingContext parsing) {
parsing.reporter.internalError(this, 'parseNode not implemented on $this.');
return null;
}
@@ -109,12 +109,6 @@
return enclosingElement != null && enclosingElement.isCompilationUnit;
}
- bool get isAssignable {
- if (isFinal || isConst) return false;
- if (isFunction || isConstructor) return false;
- return true;
- }
-
Token get position => null;
SourceSpan get sourcePosition {
@@ -177,19 +171,6 @@
return null;
}
- Element get outermostEnclosingMemberOrTopLevel {
- // TODO(lrn): Why is this called "Outermost"?
- // TODO(johnniwinther): Clean up this method: This method does not return
- // the outermost for elements in closure classses, but some call-sites rely
- // on that behavior.
- for (Element e = this; e != null; e = e.enclosingElement) {
- if (e.isClassMember || e.isTopLevel) {
- return e;
- }
- }
- return null;
- }
-
/**
* Creates the scope for this element.
*/
@@ -1328,7 +1309,7 @@
TypedefType computeType(Resolution resolution) {
if (thisTypeCache != null) return thisTypeCache;
- Typedef node = parseNode(resolution.parsing);
+ Typedef node = parseNode(resolution.parsingContext);
setThisAndRawTypes(createTypeVariables(node.typeParameters));
ensureResolved(resolution);
return thisTypeCache;
@@ -1401,7 +1382,7 @@
metadataInternal = metadata;
}
- VariableDefinitions parseNode(Element element, Parsing parsing) {
+ VariableDefinitions parseNode(Element element, ParsingContext parsing) {
return definitions;
}
@@ -1480,7 +1461,7 @@
return initializerCache;
}
- Node parseNode(Parsing parsing) {
+ Node parseNode(ParsingContext parsing) {
if (definitionsCache != null) return definitionsCache;
VariableDefinitions definitions = variables.parseNode(this, parsing);
@@ -1530,7 +1511,7 @@
if (variables.type != null) return variables.type;
// Call [parseNode] to ensure that [definitionsCache] and [initializerCache]
// are set as a consequence of calling [computeType].
- parseNode(resolution.parsing);
+ parseNode(resolution.parsingContext);
return variables.computeType(this, resolution);
}
@@ -1700,7 +1681,7 @@
Token get position => identifier.getBeginToken();
- Node parseNode(Parsing parsing) => definitions;
+ Node parseNode(ParsingContext parsing) => definitions;
DartType computeType(Resolution resolution) {
assert(invariant(this, type != null,
@@ -1860,7 +1841,7 @@
throw "internal error: AbstractFieldElement has no type";
}
- Node parseNode(Parsing parsing) {
+ Node parseNode(ParsingContext parsing) {
throw "internal error: AbstractFieldElement has no node";
}
@@ -2114,7 +2095,7 @@
bool get hasNode => true;
- FunctionExpression parseNode(Parsing parsing) => node;
+ FunctionExpression parseNode(ParsingContext parsing) => node;
Token get position {
// Use the name as position if this is not an unnamed closure.
@@ -2271,7 +2252,7 @@
// error messages.
Token get position => null;
- FunctionExpression parseNode(Parsing parsing) => null;
+ FunctionExpression parseNode(ParsingContext parsing) => null;
bool get hasNode => false;
@@ -2328,24 +2309,31 @@
*/
class SynthesizedConstructorElementX extends ConstructorElementX {
final ConstructorElement definingConstructor;
- final bool isDefaultConstructor;
+ ResolvedAst _resolvedAst;
SynthesizedConstructorElementX.notForDefault(
String name, this.definingConstructor, Element enclosing)
- : isDefaultConstructor = false,
- super(name, ElementKind.GENERATIVE_CONSTRUCTOR, Modifiers.EMPTY,
- enclosing);
+ : super(name, ElementKind.GENERATIVE_CONSTRUCTOR, Modifiers.EMPTY,
+ enclosing) {
+ _resolvedAst = new SynthesizedResolvedAst(
+ this, ResolvedAstKind.FORWARDING_CONSTRUCTOR);
+ }
SynthesizedConstructorElementX.forDefault(
this.definingConstructor, Element enclosing)
- : isDefaultConstructor = true,
- super('', ElementKind.GENERATIVE_CONSTRUCTOR, Modifiers.EMPTY,
+ : super('', ElementKind.GENERATIVE_CONSTRUCTOR, Modifiers.EMPTY,
enclosing) {
functionSignature = new FunctionSignatureX(
type: new FunctionType.synthesized(enclosingClass.thisType));
+ _resolvedAst =
+ new SynthesizedResolvedAst(this, ResolvedAstKind.DEFAULT_CONSTRUCTOR);
}
- FunctionExpression parseNode(Parsing parsing) => null;
+ bool get isDefaultConstructor {
+ return _resolvedAst.kind == ResolvedAstKind.DEFAULT_CONSTRUCTOR;
+ }
+
+ FunctionExpression parseNode(ParsingContext parsing) => null;
bool get hasNode => false;
@@ -2355,6 +2343,10 @@
bool get isSynthesized => true;
+ bool get hasResolvedAst => true;
+
+ ResolvedAst get resolvedAst => _resolvedAst;
+
DartType get type {
if (isDefaultConstructor) {
return super.type;
@@ -2522,7 +2514,7 @@
rawTypeCache = origin.rawType;
} else if (thisTypeCache == null) {
computeThisAndRawType(
- resolution, computeTypeParameters(resolution.parsing));
+ resolution, computeTypeParameters(resolution.parsingContext));
}
return thisTypeCache;
}
@@ -2544,7 +2536,7 @@
return new InterfaceType(this, typeArguments);
}
- List<DartType> computeTypeParameters(Parsing parsing);
+ List<DartType> computeTypeParameters(ParsingContext parsing);
bool get isObject {
assert(invariant(this, isResolved,
@@ -2676,7 +2668,7 @@
addMember(constructor, reporter);
}
- List<DartType> computeTypeParameters(Parsing parsing) {
+ List<DartType> computeTypeParameters(ParsingContext parsing) {
ClassNode node = parseNode(parsing);
return createTypeVariables(node.typeParameters);
}
@@ -2694,6 +2686,31 @@
}
}
+/// This element is used to encode an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
+/// where the `A` class is encoded using this element.
+///
class EnumClassElementX extends ClassElementX
implements EnumClassElement, DeclarationSite {
final Enum node;
@@ -2712,14 +2729,15 @@
bool get isEnumClass => true;
@override
- Node parseNode(Parsing parsing) => node;
+ Node parseNode(ParsingContext parsing) => node;
@override
accept(ElementVisitor visitor, arg) {
return visitor.visitEnumClassElement(this, arg);
}
- List<DartType> computeTypeParameters(Parsing parsing) => const <DartType>[];
+ List<DartType> computeTypeParameters(ParsingContext parsing) =>
+ const <DartType>[];
List<FieldElement> get enumValues {
assert(invariant(this, _enumValues != null,
@@ -2737,6 +2755,31 @@
DeclarationSite get declarationSite => this;
}
+/// This element is used to encode the implicit constructor in an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
+/// where the `const A(...)` constructor is encoded using this element.
+///
class EnumConstructorElementX extends ConstructorElementX {
final FunctionExpression node;
@@ -2752,12 +2795,37 @@
bool get hasNode => true;
@override
- FunctionExpression parseNode(Parsing parsing) => node;
+ FunctionExpression parseNode(ParsingContext parsing) => node;
@override
SourceSpan get sourcePosition => enclosingClass.sourcePosition;
}
+/// This element is used to encode the implicit methods in an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
+/// where the `toString` method is encoded using this element.
+///
class EnumMethodElementX extends MethodElementX {
final FunctionExpression node;
@@ -2769,12 +2837,38 @@
bool get hasNode => true;
@override
- FunctionExpression parseNode(Parsing parsing) => node;
+ FunctionExpression parseNode(ParsingContext parsing) => node;
@override
SourceSpan get sourcePosition => enclosingClass.sourcePosition;
}
+/// This element is used to encode the initializing formal of the implicit
+/// constructor in an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
+/// where the `this.index` formal is encoded using this element.
+///
class EnumFormalElementX extends InitializingFormalElementX {
EnumFormalElementX(
ConstructorElement constructor,
@@ -2789,6 +2883,31 @@
SourceSpan get sourcePosition => enclosingClass.sourcePosition;
}
+/// This element is used to encode the implicitly fields in an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
+/// where the `index` and `values` fields are encoded using this element.
+///
class EnumFieldElementX extends FieldElementX {
EnumFieldElementX(Identifier name, EnumClassElementX enumClass,
VariableList variableList, Node definition,
@@ -2803,6 +2922,31 @@
SourceSpan get sourcePosition => enclosingClass.sourcePosition;
}
+/// This element is used to encode the constant value in an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
+/// where the `b` and `c` fields are encoded using this element.
+///
class EnumConstantElementX extends EnumFieldElementX
implements EnumConstantElement {
final int index;
@@ -2818,8 +2962,7 @@
@override
SourceSpan get sourcePosition {
- return new SourceSpan(
- enclosingClass.sourcePosition.uri,
+ return new SourceSpan(enclosingClass.sourcePosition.uri,
position.charOffset, position.charEnd);
}
}
@@ -2848,7 +2991,7 @@
Token get position => node.getBeginToken();
- Node parseNode(Parsing parsing) => node;
+ Node parseNode(ParsingContext parsing) => node;
void addMember(Element element, DiagnosticReporter reporter) {
throw new UnsupportedError("Cannot add member to $this.");
@@ -2868,7 +3011,7 @@
addConstructor(constructor);
}
- List<DartType> computeTypeParameters(Parsing parsing) {
+ List<DartType> computeTypeParameters(ParsingContext parsing) {
NamedMixinApplication named = node.asNamedMixinApplication();
if (named == null) {
throw new SpannableAssertionFailure(
@@ -2992,7 +3135,7 @@
bool get hasNode => true;
- Node parseNode(Parsing parsing) => node;
+ Node parseNode(ParsingContext parsing) => node;
Token get position => node.getBeginToken();
@@ -3055,7 +3198,7 @@
return this;
}
- Node parseNode(Parsing parsing);
+ Node parseNode(ParsingContext parsing);
String toString() => 'MetadataAnnotation($constant, $resolutionState)';
}
@@ -3066,7 +3209,7 @@
ParameterMetadataAnnotation(Metadata this.metadata);
- Node parseNode(Parsing parsing) => metadata.expression;
+ Node parseNode(ParsingContext parsing) => metadata.expression;
Token get beginToken => metadata.getBeginToken();
@@ -3126,7 +3269,15 @@
}
ResolvedAst get resolvedAst {
- return new ResolvedAst(
- declaration, definingElement.node, definingElement.treeElements);
+ Node node = definingElement.node;
+ Node body;
+ if (definingElement.isField) {
+ FieldElement field = definingElement;
+ body = field.initializer;
+ } else if (node != null && node.asFunctionExpression() != null) {
+ body = node.asFunctionExpression().body;
+ }
+ return new ParsedResolvedAst(
+ declaration, node, body, definingElement.treeElements);
}
}
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index ff3c21c..8f1f1b7 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -6,13 +6,13 @@
import 'dart:collection' show Queue;
-import 'common.dart';
+import 'common/codegen.dart' show CodegenWorkItem;
import 'common/names.dart' show Identifiers;
import 'common/resolution.dart' show Resolution;
-import 'common/work.dart' show ItemCompilationContext, WorkItem;
-import 'common/tasks.dart' show CompilerTask, DeferredAction, DeferredTask;
-import 'common/codegen.dart' show CodegenWorkItem;
import 'common/resolution.dart' show ResolutionWorkItem;
+import 'common/tasks.dart' show CompilerTask, DeferredAction, DeferredTask;
+import 'common/work.dart' show ItemCompilationContext, WorkItem;
+import 'common.dart';
import 'compiler.dart' show Compiler;
import 'dart_types.dart' show DartType, InterfaceType;
import 'elements/elements.dart'
@@ -25,10 +25,8 @@
Elements,
FunctionElement,
LibraryElement,
- LocalFunctionElement,
Member,
MemberElement,
- MethodElement,
Name,
TypedElement,
TypedefElement;
@@ -41,7 +39,7 @@
show DynamicUse, StaticUse, StaticUseKind, TypeUse, TypeUseKind;
import 'universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitor;
-import 'util/util.dart' show Link, Setlet;
+import 'util/util.dart' show Setlet;
typedef ItemCompilationContext ItemCompilationContextCreator();
@@ -703,6 +701,8 @@
void forgetElement(Element element) {
universe.forgetElement(element, compiler);
_processedClasses.remove(element);
+ instanceMembersByName[element.name]?.remove(element);
+ instanceFunctionsByName[element.name]?.remove(element);
}
}
diff --git a/pkg/compiler/lib/src/id_generator.dart b/pkg/compiler/lib/src/id_generator.dart
index 4c92ea9..9107c7a 100644
--- a/pkg/compiler/lib/src/id_generator.dart
+++ b/pkg/compiler/lib/src/id_generator.dart
@@ -10,4 +10,4 @@
///
/// This identifier is guaranteed to be unique.
int getNextFreeId() => _nextFreeId++;
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index 5d4623a..78ef6bb 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -705,6 +705,7 @@
implements SemanticSendVisitor<T, dynamic> {
final Compiler compiler;
final AstElement analyzedElement;
+ final ResolvedAst resolvedAst;
final TypeSystem<T> types;
final E inferrer;
final Map<JumpTarget, List<LocalsHandler<T>>> breaksFor =
@@ -713,7 +714,8 @@
new Map<JumpTarget, List<LocalsHandler<T>>>();
LocalsHandler<T> locals;
final List<T> cascadeReceiverStack = new List<T>();
- final TreeElements elements;
+
+ TreeElements get elements => resolvedAst.elements;
bool accumulateIsChecks = false;
bool conditionIsSimple = false;
@@ -733,12 +735,11 @@
}
}
- InferrerVisitor(
- AstElement analyzedElement, this.inferrer, this.types, this.compiler,
+ InferrerVisitor(AstElement analyzedElement, this.resolvedAst, this.inferrer,
+ this.types, this.compiler,
[LocalsHandler<T> handler])
: this.analyzedElement = analyzedElement,
- this.locals = handler,
- this.elements = analyzedElement.resolvedAst.elements {
+ this.locals = handler {
if (handler != null) return;
Node node = analyzedElement.node;
FieldInitializationScope<T> fieldScope =
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index e3b2327c..b148b11 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -4,34 +4,26 @@
library simple_types_inferrer;
-import '../closure.dart' show ClosureClassMap, ClosureScope;
+import '../closure.dart' show ClosureClassMap;
import '../common.dart';
import '../common/names.dart' show Selectors;
import '../compiler.dart' show Compiler;
import '../constants/values.dart' show ConstantValue, IntConstantValue;
import '../core_types.dart' show CoreClasses, CoreTypes;
import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node;
-import '../dart_types.dart'
- show DartType, FunctionType, InterfaceType, TypeKind;
+import '../dart_types.dart' show DartType;
import '../elements/elements.dart';
import '../js_backend/js_backend.dart' as js;
import '../native/native.dart' as native;
-import '../resolution/tree_elements.dart' show TreeElements;
import '../resolution/operators.dart' as op;
+import '../resolution/tree_elements.dart' show TreeElements;
import '../tree/tree.dart' as ast;
-import '../types/types.dart'
- show
- TypesInferrer,
- FlatTypeMask,
- TypeMask,
- ContainerTypeMask,
- ValueTypeMask;
-import '../util/util.dart' show Link, Setlet;
+import '../types/types.dart' show TypeMask;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
+import '../util/util.dart' show Link, Setlet;
import '../world.dart' show ClassWorld;
-
import 'inferrer_visitor.dart';
/**
@@ -339,16 +331,24 @@
final Setlet<Entity> capturedVariables = new Setlet<Entity>();
SimpleTypeInferrerVisitor.internal(
- analyzedElement, this.outermostElement, inferrer, compiler, locals)
- : super(analyzedElement, inferrer, inferrer.types, compiler, locals),
+ AstElement analyzedElement,
+ ResolvedAst resolvedAst,
+ this.outermostElement,
+ inferrer,
+ compiler,
+ locals)
+ : super(analyzedElement, resolvedAst, inferrer, inferrer.types, compiler,
+ locals),
this.inferrer = inferrer {
assert(outermostElement != null);
}
- SimpleTypeInferrerVisitor(Element element, Compiler compiler,
- InferrerEngine<T, TypeSystem<T>> inferrer, [LocalsHandler<T> handler])
+ SimpleTypeInferrerVisitor(Element element, ResolvedAst resolvedAst,
+ Compiler compiler, InferrerEngine<T, TypeSystem<T>> inferrer,
+ [LocalsHandler<T> handler])
: this.internal(
element,
+ resolvedAst,
element.outermostEnclosingMemberOrTopLevel.implementation,
inferrer,
compiler,
@@ -375,8 +375,8 @@
// be handled specially, in that we are computing their LUB at
// each update, and reading them yields the type that was found in a
// previous analysis of [outermostElement].
- ClosureClassMap closureData = compiler.closureToClassMapper
- .computeClosureToClassMapping(analyzedElement, node, elements);
+ ClosureClassMap closureData =
+ compiler.closureToClassMapper.computeClosureToClassMapping(resolvedAst);
closureData.forEachCapturedVariable((variable, field) {
locals.setCaptured(variable, field);
});
@@ -402,8 +402,8 @@
SimpleTypeInferrerVisitor visitor = this;
if (inferrer.hasAlreadyComputedTypeOfParameterDefault(element)) return;
if (element.functionDeclaration != analyzedElement) {
- visitor = new SimpleTypeInferrerVisitor(
- element.functionDeclaration, compiler, inferrer);
+ visitor = new SimpleTypeInferrerVisitor(element.functionDeclaration,
+ element.functionDeclaration.resolvedAst, compiler, inferrer);
}
T type =
(defaultValue == null) ? types.nullType : visitor.visit(defaultValue);
@@ -552,7 +552,7 @@
LocalsHandler closureLocals =
new LocalsHandler<T>.from(locals, node, useOtherTryBlock: false);
SimpleTypeInferrerVisitor visitor = new SimpleTypeInferrerVisitor<T>(
- element, compiler, inferrer, closureLocals);
+ element, element.resolvedAst, compiler, inferrer, closureLocals);
visitor.run();
inferrer.recordReturnType(element, visitor.returnType);
@@ -1513,8 +1513,7 @@
String name = element.name;
handleStaticSend(node, selector, mask, element, arguments);
if (name == 'JS' || name == 'JS_EMBEDDED_GLOBAL' || name == 'JS_BUILTIN') {
- native.NativeBehavior nativeBehavior =
- compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ native.NativeBehavior nativeBehavior = elements.getNativeData(node);
sideEffects.add(nativeBehavior.sideEffects);
return inferrer.typeOfNativeBehavior(nativeBehavior);
} else if (name == 'JS_OPERATOR_AS_PREFIX' || name == 'JS_STRING_CONCAT') {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index e19436f..1cfc52a 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -7,34 +7,31 @@
import 'dart:collection' show Queue;
import '../common.dart';
-import '../common/names.dart' show Identifiers, Names;
+import '../common/names.dart' show Identifiers;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
-import '../dart_types.dart'
- show DartType, FunctionType, InterfaceType, TypeKind;
+import '../dart_types.dart' show DartType;
import '../elements/elements.dart';
import '../js_backend/js_backend.dart' show Annotations, JavaScriptBackend;
import '../resolution/tree_elements.dart' show TreeElementMapping;
import '../tree/tree.dart' as ast
- show DartString, Node, LiteralBool, Send, SendSet, TryStatement;
+ show DartString, Node, LiteralBool, TryStatement;
+import '../types/constants.dart' show computeTypeMask;
import '../types/types.dart'
show ContainerTypeMask, MapTypeMask, TypeMask, TypesInferrer;
-import '../types/constants.dart' show computeTypeMask;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
-import '../util/util.dart' show ImmutableEmptySet, Setlet;
+import '../util/util.dart' show Setlet;
import '../world.dart' show ClassWorld;
-
-import 'inferrer_visitor.dart' show ArgumentsTypes, TypeSystem;
-import 'simple_types_inferrer.dart';
-
import 'closure_tracer.dart';
+import 'debug.dart' as debug;
+import 'inferrer_visitor.dart' show ArgumentsTypes, TypeSystem;
import 'list_tracer.dart';
import 'map_tracer.dart';
-import 'type_graph_nodes.dart';
+import 'simple_types_inferrer.dart';
import 'type_graph_dump.dart';
-import 'debug.dart' as debug;
+import 'type_graph_nodes.dart';
class TypeInformationSystem extends TypeSystem<TypeInformation> {
final Compiler compiler;
@@ -830,13 +827,13 @@
processLoopInformation();
}
- void analyze(Element element, ArgumentsTypes arguments) {
+ void analyze(AstElement element, ArgumentsTypes arguments) {
element = element.implementation;
if (analyzedElements.contains(element)) return;
analyzedElements.add(element);
- SimpleTypeInferrerVisitor visitor =
- new SimpleTypeInferrerVisitor(element, compiler, this);
+ SimpleTypeInferrerVisitor visitor = new SimpleTypeInferrerVisitor(
+ element, element.resolvedAst, compiler, this);
TypeInformation type;
reporter.withCurrentElement(element, () {
type = visitor.run();
@@ -1003,7 +1000,7 @@
bool visitingRequiredParameter = true;
signature.forEachParameter((Element parameter) {
if (signature.hasOptionalParameters &&
- parameter == signature.firstOptionalParameter) {
+ parameter == signature.optionalParameters.first) {
visitingRequiredParameter = false;
}
TypeInformation type = visitingRequiredParameter
@@ -1239,7 +1236,7 @@
// TODO(ngeoffray): Not sure why the resolver would put a null
// mapping.
if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
- TreeElementMapping mapping = element.resolvedAst.elements;
+ ResolvedAst resolvedAst = element.resolvedAst;
element = element.implementation;
if (element.impliesType) return;
assert(invariant(
@@ -1253,7 +1250,11 @@
if (element.isAbstract) return;
// Put the other operators in buckets by length, later to be added in
// length order.
- int length = mapping.getSelectorCount();
+ int length = 0;
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ TreeElementMapping mapping = resolvedAst.elements;
+ length = mapping.getSelectorCount();
+ }
max = length > max ? length : max;
Setlet<Element> set =
methodSizes.putIfAbsent(length, () => new Setlet<Element>());
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 1815539..2bc3670 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -11,12 +11,10 @@
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node;
-import '../dart_types.dart'
- show DartType, FunctionType, InterfaceType, TypeKind;
+import '../dart_types.dart' show DartType, FunctionType, TypeKind;
import '../elements/elements.dart';
import '../native/native.dart' as native;
-import '../tree/tree.dart' as ast
- show DartString, Node, LiteralBool, Send, SendSet, TryStatement;
+import '../tree/tree.dart' as ast show DartString, Node, LiteralBool, Send;
import '../types/types.dart'
show
ContainerTypeMask,
@@ -27,11 +25,10 @@
import '../universe/selector.dart' show Selector;
import '../util/util.dart' show ImmutableEmptySet, Setlet;
import '../world.dart' show ClassWorld;
-
+import 'debug.dart' as debug;
import 'inferrer_visitor.dart' show ArgumentsTypes;
import 'type_graph_inferrer.dart'
show TypeGraphInferrerEngine, TypeInformationSystem;
-import 'debug.dart' as debug;
/**
* Common class for all nodes in the graph. The current nodes are:
diff --git a/pkg/compiler/lib/src/info/send_info.dart b/pkg/compiler/lib/src/info/send_info.dart
index b0f5f1e..86f3845 100644
--- a/pkg/compiler/lib/src/info/send_info.dart
+++ b/pkg/compiler/lib/src/info/send_info.dart
@@ -8,21 +8,20 @@
import 'package:dart2js_info/src/measurements.dart';
import 'package:dart2js_info/src/util.dart' show recursiveDiagnosticString;
+import '../closure.dart';
import '../common.dart';
import '../compiler.dart' show Compiler;
+import '../constants/expressions.dart';
import '../dart_types.dart';
-import '../closure.dart';
import '../elements/elements.dart';
import '../elements/visitor.dart' show ElementVisitor;
+import '../parser/partial_elements.dart' show PartialElement;
import '../resolution/operators.dart';
import '../resolution/semantic_visitor.dart';
import '../resolution/tree_elements.dart';
-import '../constants/expressions.dart';
-import '../parser/partial_elements.dart' show PartialElement;
import '../tree/tree.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
-
import 'analysis_result.dart';
import 'naive_analysis_result.dart';
import 'trusted_types_analysis_result.dart';
@@ -34,7 +33,6 @@
return reporter.withCurrentElement(f, () {
// TODO(sigmund): enable for platform too.
if (f.library.isPlatformLibrary) return null;
- var name = _qualifiedName(f);
if (!f.hasNode) {
if (f is PartialElement) return const Measurements.unreachableFunction();
assert(f is ConstructorElement && f.isSynthesized);
@@ -64,11 +62,6 @@
});
}
-_qualifiedName(FunctionElement f) {
- var cls = f.enclosingClass;
- return (cls != null) ? '${cls.name}.${f.name}' : f.name;
-}
-
/// Visitor that categorizes data about an individual send.
class _StatsVisitor<T> extends Visitor
with SemanticSendResolvedMixin<dynamic, T>
@@ -2363,7 +2356,6 @@
return null;
}
- @override
R visitVariableElement(VariableElement e, A arg) => null;
@override
@@ -2381,7 +2373,6 @@
@override
R visitAbstractFieldElement(AbstractFieldElement e, A arg) => null;
- @override
R visitFunctionElement(FunctionElement e, A arg) => null;
@override
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 83460d5..38df221 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -8,12 +8,11 @@
library dart2js.source_information.position;
import '../common.dart';
-import '../elements/elements.dart' show AstElement, FieldElement, LocalElement;
+import '../elements/elements.dart' show AstElement, FieldElement, ResolvedAst, ResolvedAstKind;
import '../js/js.dart' as js;
-import '../js/js_source_mapping.dart';
import '../js/js_debug.dart';
+import '../js/js_source_mapping.dart';
import '../tree/tree.dart' show FunctionExpression, Node, Send;
-
import 'code_output.dart' show CodeBuffer;
import 'source_file.dart';
import 'source_information.dart';
@@ -148,16 +147,17 @@
sourceFile = element.implementation.compilationUnit.script.file,
name = computeElementNameForSourceMaps(element);
- SourceInformation buildDeclaration(AstElement element) {
- if (element.isSynthesized) {
+ SourceInformation buildDeclaration(ResolvedAst resolvedAst) {
+ if (resolvedAst.kind != ResolvedAstKind.PARSED) {
+ SourceSpan span = resolvedAst.element.sourcePosition;
return new PositionSourceInformation(new OffsetSourceLocation(
- sourceFile, element.position.charOffset, name));
+ sourceFile, span.begin, name));
} else {
return new PositionSourceInformation(
new OffsetSourceLocation(sourceFile,
- element.resolvedAst.node.getBeginToken().charOffset, name),
+ resolvedAst.node.getBeginToken().charOffset, name),
new OffsetSourceLocation(sourceFile,
- element.resolvedAst.node.getEndToken().charOffset, name));
+ resolvedAst.node.getEndToken().charOffset, name));
}
}
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index ec2b933..cf3872c 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -5,9 +5,9 @@
library dart2js.source_information;
import '../common.dart';
-import '../elements/elements.dart' show AstElement, LocalElement;
-import '../tree/tree.dart' show Node, Send;
+import '../elements/elements.dart' show AstElement, LocalElement, ResolvedAst;
import '../js/js.dart' show JavaScriptNodeSourceInformation;
+import '../tree/tree.dart' show Node;
import 'source_file.dart';
/// Interface for passing source information, for instance for use in source
@@ -56,8 +56,9 @@
/// Create a [SourceInformationBuilder] for [element].
SourceInformationBuilder forContext(AstElement element) => this;
- /// Generate [SourceInformation] the declaration of [element].
- SourceInformation buildDeclaration(AstElement element) => null;
+ /// Generate [SourceInformation] the declaration of the element in
+ /// [resolvedAst].
+ SourceInformation buildDeclaration(ResolvedAst resolvedAst) => null;
/// Generate [SourceInformation] for the generic [node].
@deprecated
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index b08477f..b749d8a 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -9,12 +9,11 @@
import '../common.dart';
import '../diagnostics/messages.dart' show MessageTemplate;
-import '../elements/elements.dart' show AstElement, LocalElement;
+import '../elements/elements.dart' show AstElement, ResolvedAst, ResolvedAstKind;
import '../js/js.dart' as js;
import '../js/js_source_mapping.dart';
import '../tokens/token.dart' show Token;
-import '../tree/tree.dart' show Node, Send;
-
+import '../tree/tree.dart' show Node;
import 'source_file.dart';
import 'source_information.dart';
@@ -61,30 +60,31 @@
// TODO(johnniwinther): Inline this in
// [StartEndSourceInformationBuilder.buildDeclaration].
static StartEndSourceInformation _computeSourceInformation(
- AstElement element) {
- AstElement implementation = element.implementation;
- SourceFile sourceFile = implementation.compilationUnit.script.file;
- String name = computeElementNameForSourceMaps(element);
- Node node = implementation.node;
- Token beginToken;
- Token endToken;
- if (node == null) {
+ ResolvedAst resolvedAst) {
+ String name = computeElementNameForSourceMaps(resolvedAst.element);
+ SourceFile sourceFile;
+ int begin;
+ int end;
+ if (resolvedAst.kind != ResolvedAstKind.PARSED) {
// Synthesized node. Use the enclosing element for the location.
- beginToken = endToken = element.position;
+ sourceFile = resolvedAst.element.compilationUnit.script.file;
+ begin = end = resolvedAst.element.sourcePosition.begin;
} else {
- beginToken = node.getBeginToken();
- endToken = node.getEndToken();
+ AstElement implementation = resolvedAst.element.implementation;
+ sourceFile = implementation.compilationUnit.script.file;
+ Node node = resolvedAst.node;
+ begin = node.getBeginToken().charOffset;
+ end = node.getEndToken().charOffset;
}
// TODO(johnniwinther): find the right sourceFile here and remove offset
// checks below.
SourceLocation sourcePosition, endSourcePosition;
- if (beginToken.charOffset < sourceFile.length) {
+ if (begin < sourceFile.length) {
sourcePosition =
- new OffsetSourceLocation(sourceFile, beginToken.charOffset, name);
+ new OffsetSourceLocation(sourceFile, begin, name);
}
- if (endToken.charOffset < sourceFile.length) {
- endSourcePosition =
- new OffsetSourceLocation(sourceFile, endToken.charOffset, name);
+ if (end < sourceFile.length) {
+ endSourcePosition = new OffsetSourceLocation(sourceFile, end, name);
}
return new StartEndSourceInformation(sourcePosition, endSourcePosition);
}
@@ -162,8 +162,8 @@
: sourceFile = element.compilationUnit.script.file,
name = computeElementNameForSourceMaps(element);
- SourceInformation buildDeclaration(AstElement element) {
- return StartEndSourceInformation._computeSourceInformation(element);
+ SourceInformation buildDeclaration(ResolvedAst resolvedAst) {
+ return StartEndSourceInformation._computeSourceInformation(resolvedAst);
}
SourceLocation sourceFileLocationForToken(Token token) {
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index cefac18..bad0d12 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -5,16 +5,16 @@
library js;
import 'package:js_ast/js_ast.dart';
-export 'package:js_ast/js_ast.dart';
import '../common.dart';
import '../compiler.dart' show Compiler;
import '../dump_info.dart' show DumpInfoTask;
-import '../io/code_output.dart' show CodeBuffer, CodeOutput;
+import '../io/code_output.dart' show CodeBuffer;
import '../js_emitter/js_emitter.dart' show USE_LAZY_EMITTER;
-
import 'js_source_mapping.dart';
+export 'package:js_ast/js_ast.dart';
+
String prettyPrint(Node node, Compiler compiler,
{bool allowVariableMinification: true,
Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer}) {
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
index 86b2601..df49903 100644
--- a/pkg/compiler/lib/src/js/js_source_mapping.dart
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -4,11 +4,10 @@
library js.source_mapping;
-import 'js.dart';
-import '../io/code_output.dart'
- show BufferedCodeOutput, CodeBuffer, SourceLocations;
+import '../io/code_output.dart' show BufferedCodeOutput, SourceLocations;
import '../io/source_information.dart'
show SourceLocation, SourceInformation, SourceInformationStrategy;
+import 'js.dart';
/// [SourceInformationStrategy] that can associate source information with
/// JavaScript output.
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 7f751db..0e8c98e 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -511,6 +511,8 @@
final BackendHelpers helpers;
final BackendImpacts impacts;
+ final JSFrontendAccess frontend;
+
JavaScriptBackend(Compiler compiler,
{bool generateSourceMap: true,
bool useStartupEmitter: false,
@@ -529,6 +531,7 @@
: const JavaScriptSourceInformationStrategy(),
helpers = new BackendHelpers(compiler),
impacts = new BackendImpacts(compiler),
+ frontend = new JSFrontendAccess(compiler),
super(compiler) {
emitter = new CodeEmitterTask(
compiler, namer, generateSourceMap, useStartupEmitter);
@@ -619,7 +622,7 @@
assert(invariant(element, element.isDeclaration, message: ""));
if (element == helpers.streamIteratorConstructor ||
element == helpers.compiler.symbolConstructor ||
- element == helpers.compiler.symbolValidatedConstructor ||
+ helpers.isSymbolValidatedConstructor(element) ||
element == helpers.syncCompleterConstructor ||
element == coreClasses.symbolClass ||
element == helpers.objectNoSuchMethod) {
@@ -1291,16 +1294,16 @@
}
/// Called when resolving a call to a foreign function.
- void registerForeignCall(Send node, Element element,
+ native.NativeBehavior resolveForeignCall(Send node, Element element,
CallStructure callStructure, ForeignResolver resolver) {
native.NativeResolutionEnqueuer nativeEnqueuer =
compiler.enqueuer.resolution.nativeEnqueuer;
if (element.name == 'JS') {
- nativeEnqueuer.registerJsCall(node, resolver);
+ return nativeEnqueuer.resolveJsCall(node, resolver);
} else if (element.name == 'JS_EMBEDDED_GLOBAL') {
- nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
+ return nativeEnqueuer.resolveJsEmbeddedGlobalCall(node, resolver);
} else if (element.name == 'JS_BUILTIN') {
- nativeEnqueuer.registerJsBuiltinCall(node, resolver);
+ return nativeEnqueuer.resolveJsBuiltinCall(node, resolver);
} else if (element.name == 'JS_INTERCEPTOR_CONSTANT') {
// The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
// a class that will be instantiated outside the program by attaching a
@@ -1312,13 +1315,16 @@
TypeConstantExpression typeConstant = constant;
if (typeConstant.type is InterfaceType) {
resolver.registerInstantiatedType(typeConstant.type);
- return;
+ // No native behavior for this call.
+ return null;
}
}
}
reporter.reportErrorMessage(
node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
}
+ // No native behavior for this call.
+ return null;
}
void enableNoSuchMethod(Enqueuer world) {
@@ -1443,8 +1449,16 @@
WorldImpact codegen(CodegenWorkItem work) {
Element element = work.element;
if (compiler.elementHasCompileTimeError(element)) {
- generatedCode[element] = jsAst.js(
- "function () { throw new Error('Compile time error in $element') }");
+ DiagnosticMessage message =
+ // If there's more than one error, the first is probably most
+ // informative, as the following errors may be side-effects of the
+ // first error.
+ compiler.elementsWithCompileTimeErrors[element].first;
+ String messageText = message.message.computeMessage();
+ jsAst.LiteralString messageLiteral =
+ js.escapedString("Compile time error in $element: $messageText");
+ generatedCode[element] = js(
+ "function () { throw new Error(#); }", [messageLiteral]);
return const CodegenImpact();
}
var kind = element.kind;
@@ -2252,7 +2266,8 @@
lookupMapAnalysis.onCodegenStart();
}
- void onElementResolved(Element element, TreeElements elements) {
+ @override
+ void onElementResolved(Element element) {
if (element.isMalformed) {
// Elements that are marker as malformed during parsing or resolution
// might be registered here. These should just be ignored.
@@ -2474,6 +2489,32 @@
}
}
+class JSFrontendAccess implements Frontend {
+ final Compiler compiler;
+
+ JSFrontendAccess(this.compiler);
+
+ Resolution get resolution => compiler.resolution;
+
+ @override
+ ResolutionImpact getResolutionImpact(Element element) {
+ return resolution.getResolutionImpact(element);
+ }
+
+ @override
+ ResolvedAst getResolvedAst(Element element) {
+ if (element is SynthesizedCallMethodElementX) {
+ return element.resolvedAst;
+ } else if (element is ConstructorBodyElementX) {
+ return element.resolvedAst;
+ } else {
+ assert(invariant(element, resolution.hasResolvedAst(element.declaration),
+ message: 'No ResolvedAst for $element'));
+ return resolution.getResolvedAst(element.declaration);
+ }
+ }
+}
+
/// Handling of special annotations for tests.
class Annotations {
static final Uri PACKAGE_EXPECT =
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index aac308d..5863104 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -18,8 +18,11 @@
EnumClassElement,
FunctionElement,
LibraryElement,
- MethodElement;
+ MethodElement,
+ PublicName;
import '../library_loader.dart' show LoadedLibraries;
+import '../universe/call_structure.dart' show CallStructure;
+import '../universe/selector.dart' show Selector;
import 'js_backend.dart';
@@ -174,6 +177,28 @@
/// Holds the class for the [JsBuiltins] enum.
EnumClassElement jsBuiltinEnum;
+ ClassElement _symbolImplementationClass;
+ ClassElement get symbolImplementationClass {
+ return _symbolImplementationClass ??= find(internalLibrary, 'Symbol');
+ }
+
+ final Selector symbolValidatedConstructorSelector =
+ new Selector.call(const PublicName('validated'), CallStructure.ONE_ARG);
+
+ ConstructorElement _symbolValidatedConstructor;
+
+ bool isSymbolValidatedConstructor(Element element) {
+ if (_symbolValidatedConstructor != null) {
+ return element == _symbolValidatedConstructor;
+ }
+ return false;
+ }
+
+ ConstructorElement get symbolValidatedConstructor {
+ return _symbolValidatedConstructor ??= _findConstructor(
+ symbolImplementationClass, symbolValidatedConstructorSelector.name);
+ }
+
// TODO(johnniwinther): Make these private.
// TODO(johnniwinther): Split into findHelperFunction and findHelperClass and
// add a check that the element has the expected kind.
@@ -187,6 +212,14 @@
return element;
}
+ ConstructorElement _findConstructor(ClassElement cls, String name) {
+ cls.ensureResolved(resolution);
+ ConstructorElement constructor = cls.lookupConstructor(name);
+ assert(invariant(cls, constructor != null,
+ message: "Constructor '$name' not found in '${cls}'."));
+ return constructor;
+ }
+
void onLibraryCreated(LibraryElement library) {
Uri uri = library.canonicalUri;
if (uri == DART_JS_HELPER) {
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 3edac4f..ee1dab9 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -291,8 +291,8 @@
BackendImpact get symbolConstructor {
if (_symbolConstructor == null) {
- _symbolConstructor = new BackendImpact(
- staticUses: [helpers.compiler.symbolValidatedConstructor]);
+ _symbolConstructor =
+ new BackendImpact(staticUses: [helpers.symbolValidatedConstructor]);
}
return _symbolConstructor;
}
diff --git a/pkg/compiler/lib/src/js_backend/backend_serialization.dart b/pkg/compiler/lib/src/js_backend/backend_serialization.dart
index c7c2039..cc7cc03f 100644
--- a/pkg/compiler/lib/src/js_backend/backend_serialization.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_serialization.dart
@@ -5,13 +5,26 @@
library js_backend.serialization;
import '../common/backend_api.dart' show BackendSerialization;
+import '../dart_types.dart';
import '../elements/elements.dart';
+import '../js/js.dart' as js;
+import '../native/native.dart';
import '../serialization/serialization.dart'
show DeserializerPlugin, ObjectDecoder, ObjectEncoder, SerializerPlugin;
import '../serialization/keys.dart';
+import '../universe/side_effects.dart';
import 'js_backend.dart';
const String _BACKEND_DATA_TAG = 'jsBackendData';
+const Key DART_TYPES_RETURNED = const Key('dartTypesReturned');
+const Key SPECIAL_TYPES_RETURNED = const Key('specialTypesReturned');
+const Key DART_TYPES_INSTANTIATED = const Key('dartTypesInstantiated');
+const Key SPECIAL_TYPES_INSTANTIATED = const Key('specialTypesInstantiated');
+const Key CODE_TEMPLATE = const Key('codeTemplate');
+const Key SIDE_EFFECTS = const Key('sideEffects');
+const Key THROW_BEHAVIOR = const Key('throwBehavior');
+const Key IS_ALLOCATION = const Key('isAllocation');
+const Key USE_GVN = const Key('useGvn');
class JavaScriptBackendSerialization implements BackendSerialization {
final JavaScriptBackendSerializer serializer;
@@ -22,6 +35,10 @@
deserializer = new JavaScriptBackendDeserializer(backend);
}
+const Key JS_INTEROP_NAME = const Key('jsInteropName');
+const Key NATIVE_MEMBER_NAME = const Key('nativeMemberName');
+const Key NATIVE_CLASS_TAG_INFO = const Key('nativeClassTagInfo');
+
class JavaScriptBackendSerializer implements SerializerPlugin {
final JavaScriptBackend backend;
@@ -29,13 +46,58 @@
@override
void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
- // TODO(johnniwinther): Add more data, e.g. js-interop names, native tags,
- // etc.
- String nativeName = backend.nativeData.nativeMemberName[element];
- if (nativeName != null) {
- ObjectEncoder encoder = createEncoder(_BACKEND_DATA_TAG);
- encoder.setString(Key.NAME, nativeName);
+ ObjectEncoder encoder;
+ ObjectEncoder getEncoder() {
+ return encoder ??= createEncoder(_BACKEND_DATA_TAG);
}
+
+ String jsInteropName = backend.nativeData.jsInteropNames[element];
+ if (jsInteropName != null) {
+ getEncoder().setString(JS_INTEROP_NAME, jsInteropName);
+ }
+ String nativeMemberName = backend.nativeData.nativeMemberName[element];
+ if (nativeMemberName != null) {
+ getEncoder().setString(NATIVE_MEMBER_NAME, nativeMemberName);
+ }
+ String nativeClassTagInfo = backend.nativeData.nativeClassTagInfo[element];
+ if (nativeClassTagInfo != null) {
+ getEncoder().setString(NATIVE_CLASS_TAG_INFO, nativeClassTagInfo);
+ }
+ }
+
+ /// Returns a list of the [DartType]s in [types].
+ static List<DartType> filterDartTypes(List types) {
+ return types.where((type) => type is DartType).toList();
+ }
+
+ /// Returns a list of the names of the [SpecialType]s in [types].
+ static List<String> filterSpecialTypes(List types) {
+ return types
+ .where((type) => type is SpecialType)
+ .map((SpecialType type) => type.name)
+ .toList();
+ }
+
+ @override
+ void onData(NativeBehavior behavior, ObjectEncoder encoder) {
+ encoder.setTypes(
+ DART_TYPES_RETURNED, filterDartTypes(behavior.typesReturned));
+ encoder.setStrings(
+ SPECIAL_TYPES_RETURNED, filterSpecialTypes(behavior.typesReturned));
+
+ encoder.setTypes(
+ DART_TYPES_INSTANTIATED, filterDartTypes(behavior.typesInstantiated));
+ encoder.setStrings(SPECIAL_TYPES_INSTANTIATED,
+ filterSpecialTypes(behavior.typesInstantiated));
+
+ if (behavior.codeTemplateText != null) {
+ encoder.setString(CODE_TEMPLATE, behavior.codeTemplateText);
+ }
+
+ encoder.setInt(SIDE_EFFECTS, behavior.sideEffects.flags);
+ encoder.setEnum(THROW_BEHAVIOR, behavior.throwBehavior);
+ encoder.setBool(IS_ALLOCATION, behavior.isAllocation);
+ encoder.setBool(USE_GVN, behavior.useGvn);
}
}
@@ -48,8 +110,52 @@
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
ObjectDecoder decoder = getDecoder(_BACKEND_DATA_TAG);
if (decoder != null) {
- String nativeName = decoder.getString(Key.NAME);
- backend.nativeData.nativeMemberName[element] = nativeName;
+ String jsInteropName =
+ decoder.getString(JS_INTEROP_NAME, isOptional: true);
+ if (jsInteropName != null) {
+ backend.nativeData.jsInteropNames[element] = jsInteropName;
+ }
+ String nativeMemberName =
+ decoder.getString(NATIVE_MEMBER_NAME, isOptional: true);
+ if (nativeMemberName != null) {
+ backend.nativeData.nativeMemberName[element] = nativeMemberName;
+ }
+ String nativeClassTagInfo =
+ decoder.getString(NATIVE_CLASS_TAG_INFO, isOptional: true);
+ if (nativeClassTagInfo != null) {
+ backend.nativeData.nativeClassTagInfo[element] = nativeClassTagInfo;
+ }
}
}
+
+ @override
+ NativeBehavior onData(ObjectDecoder decoder) {
+ SideEffects sideEffects =
+ new SideEffects.fromFlags(decoder.getInt(SIDE_EFFECTS));
+ NativeBehavior behavior = new NativeBehavior.internal(sideEffects);
+
+ behavior.typesReturned
+ .addAll(decoder.getTypes(DART_TYPES_RETURNED, isOptional: true));
+ behavior.typesReturned.addAll(decoder
+ .getStrings(SPECIAL_TYPES_RETURNED, isOptional: true)
+ .map(SpecialType.fromName));
+
+ behavior.typesReturned
+ .addAll(decoder.getTypes(DART_TYPES_INSTANTIATED, isOptional: true));
+ behavior.typesReturned.addAll(decoder
+ .getStrings(SPECIAL_TYPES_INSTANTIATED, isOptional: true)
+ .map(SpecialType.fromName));
+
+ behavior.codeTemplateText =
+ decoder.getString(CODE_TEMPLATE, isOptional: true);
+ if (behavior.codeTemplateText != null) {
+ behavior.codeTemplate = js.js.parseForeignJS(behavior.codeTemplateText);
+ }
+
+ behavior.throwBehavior =
+ decoder.getEnum(THROW_BEHAVIOR, NativeThrowBehavior.values);
+ behavior.isAllocation = decoder.getBool(IS_ALLOCATION);
+ behavior.useGvn = decoder.getBool(USE_GVN);
+ return behavior;
+ }
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index eafef0e..096573f 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -4,22 +4,21 @@
library code_generator_dependencies;
-import '../backend_helpers.dart' show BackendHelpers;
-import '../js_backend.dart';
-
import '../../common.dart';
import '../../common/codegen.dart' show CodegenRegistry;
import '../../compiler.dart' show Compiler;
import '../../constants/values.dart';
-import '../../dart_types.dart' show DartType, TypeVariableType, InterfaceType;
-import '../../enqueue.dart' show CodegenEnqueuer;
+import '../../dart_types.dart' show DartType, TypeVariableType;
import '../../elements/elements.dart';
-import '../../js_emitter/js_emitter.dart';
+import '../../enqueue.dart' show CodegenEnqueuer;
import '../../js/js.dart' as js;
+import '../../js_emitter/js_emitter.dart';
import '../../native/native.dart' show NativeBehavior;
+import '../../types/types.dart';
import '../../universe/selector.dart' show Selector;
import '../../world.dart' show ClassWorld;
-import '../../types/types.dart';
+import '../backend_helpers.dart' show BackendHelpers;
+import '../js_backend.dart';
/// Encapsulates the dependencies of the function-compiler to the compiler,
/// backend and emitter.
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 061e44a..cf21b0b 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -351,6 +351,6 @@
js.Node attachPosition(js.Node node, AstElement element) {
return node.withSourceInformation(sourceInformationFactory
.createBuilderForContext(element)
- .buildDeclaration(element));
+ .buildDeclaration(backend.frontend.getResolvedAst(element)));
}
}
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index ca13518..6be55db 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -4,7 +4,7 @@
library js_backend;
-import 'dart:async' show EventSink, Future;
+import 'dart:async' show Future;
import 'dart:collection' show HashMap;
import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
@@ -13,17 +13,22 @@
import '../closure.dart';
import '../common.dart';
import '../common/backend_api.dart'
- show Backend, BackendSerialization, ImpactTransformer, ForeignResolver;
-import '../common/codegen.dart'
- show CodegenImpact, CodegenRegistry, CodegenWorkItem;
+ show Backend, ImpactTransformer, ForeignResolver;
+import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem;
import '../common/names.dart' show Identifiers, Names, Selectors, Uris;
import '../common/registry.dart' show EagerRegistry, Registry;
-import '../common/tasks.dart' show CompilerTask;
import '../common/resolution.dart'
- show Feature, ListLiteralUse, MapLiteralUse, Resolution, ResolutionImpact;
+ show
+ Feature,
+ Frontend,
+ ListLiteralUse,
+ MapLiteralUse,
+ Resolution,
+ ResolutionImpact;
+import '../common/tasks.dart' show CompilerTask;
import '../common/work.dart' show ItemCompilationContext;
-import '../compiler.dart' show Compiler;
import '../compile_time_constants.dart';
+import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
@@ -33,11 +38,12 @@
import '../diagnostics/invariant.dart' show DEBUG_MODE;
import '../dump_info.dart' show DumpInfoTask;
import '../elements/elements.dart';
+import '../elements/modelx.dart' show ConstructorBodyElementX;
import '../elements/visitor.dart' show BaseElementVisitor;
import '../enqueue.dart' show Enqueuer, ResolutionEnqueuer;
import '../io/code_output.dart';
-import '../io/source_information.dart' show SourceInformationStrategy;
import '../io/position_information.dart' show PositionSourceInformationStrategy;
+import '../io/source_information.dart' show SourceInformationStrategy;
import '../io/start_end_information.dart'
show StartEndSourceInformationStrategy;
import '../js/js.dart' as jsAst;
@@ -45,18 +51,13 @@
import '../js/js_source_mapping.dart' show JavaScriptSourceInformationStrategy;
import '../js/rewrite_async.dart';
import '../js_emitter/js_emitter.dart'
- show
- CodeEmitterTask,
- Emitter,
- MetadataCollector,
- Placeholder,
- USE_LAZY_EMITTER;
+ show CodeEmitterTask, MetadataCollector, Placeholder;
import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
import '../native/native.dart' as native;
import '../resolution/tree_elements.dart' show TreeElements;
import '../ssa/builder.dart' show SsaFunctionCompiler;
-import '../ssa/nodes.dart' show HTypeConversion, HInstruction;
import '../ssa/codegen.dart' show SsaCodeGenerator;
+import '../ssa/nodes.dart' show HTypeConversion, HInstruction;
import '../tree/tree.dart';
import '../types/types.dart';
import '../universe/call_structure.dart' show CallStructure;
@@ -74,15 +75,14 @@
import '../util/characters.dart';
import '../util/util.dart';
import '../world.dart' show ClassWorld;
-
import 'backend_helpers.dart';
import 'backend_impact.dart';
import 'backend_serialization.dart' show JavaScriptBackendSerialization;
import 'codegen/task.dart';
import 'constant_system_javascript.dart';
-import 'native_data.dart' show NativeData;
import 'js_interop_analysis.dart' show JsInteropAnalysis;
import 'lookup_map_analysis.dart' show LookupMapAnalysis;
+import 'native_data.dart' show NativeData;
import 'patch_resolver.dart';
part 'backend.dart';
@@ -90,8 +90,8 @@
part 'constant_emitter.dart';
part 'constant_handler_javascript.dart';
part 'custom_elements_analysis.dart';
-part 'frequency_namer.dart';
part 'field_naming_mixin.dart';
+part 'frequency_namer.dart';
part 'minify_namer.dart';
part 'namer.dart';
part 'namer_names.dart';
diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
index 2798ac3..448f979 100644
--- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
@@ -5,15 +5,9 @@
/// Analysis to determine how to generate code for typed JavaScript interop.
library compiler.src.js_backend.js_interop_analysis;
-import '../diagnostics/messages.dart' show MessageKind;
import '../constants/values.dart'
- show
- ConstantValue,
- ConstructedConstantValue,
- ListConstantValue,
- NullConstantValue,
- StringConstantValue,
- TypeConstantValue;
+ show ConstantValue, ConstructedConstantValue, StringConstantValue;
+import '../diagnostics/messages.dart' show MessageKind;
import '../elements/elements.dart'
show
ClassElement,
@@ -23,12 +17,10 @@
LibraryElement,
ParameterElement,
MetadataAnnotation;
-
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
import '../universe/selector.dart' show Selector;
import '../universe/universe.dart' show SelectorConstraints;
-
import 'backend_helpers.dart' show BackendHelpers;
import 'js_backend.dart' show JavaScriptBackend;
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
index a1543bd..ee4272a 100644
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -5,6 +5,8 @@
/// Analysis to determine how to generate code for `LookupMap`s.
library compiler.src.js_backend.lookup_map_analysis;
+import 'package:pub_semver/pub_semver.dart';
+
import '../common.dart';
import '../common/registry.dart' show Registry;
import '../compiler.dart' show Compiler;
@@ -17,19 +19,10 @@
StringConstantValue,
TypeConstantValue;
import '../dart_types.dart' show DartType;
+import '../dart_types.dart' show InterfaceType;
import '../elements/elements.dart'
- show
- ClassElement,
- Element,
- Elements,
- FieldElement,
- FunctionElement,
- FunctionSignature,
- LibraryElement,
- VariableElement;
+ show ClassElement, FieldElement, LibraryElement, VariableElement;
import 'js_backend.dart' show JavaScriptBackend;
-import '../dart_types.dart' show DynamicType, InterfaceType;
-import 'package:pub_semver/pub_semver.dart';
/// An analysis and optimization to remove unused entries from a `LookupMap`.
///
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 70d7eb7..4e8fe30 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -346,7 +346,6 @@
/// The non-minifying namer's [callPrefix] with a dollar after it.
static const String _callPrefixDollar = r'call$';
- static final jsAst.Name _literalSuper = new StringBackedName("super");
static final jsAst.Name _literalDollar = new StringBackedName(r'$');
static final jsAst.Name _literalUnderscore = new StringBackedName('_');
static final jsAst.Name literalPlus = new StringBackedName('+');
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 cb4dc4f..0e02c6c 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -4,20 +4,13 @@
library dart2js.js_emitter.full_emitter;
-import 'dart:convert';
import 'dart:collection' show HashMap;
+import 'dart:convert';
import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
import 'package:js_runtime/shared/embedded_names.dart'
show JsBuiltin, JsGetName;
-import '../headers.dart';
-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 '../constant_ordering.dart' show deepCompareConstants;
-
import '../../common.dart';
import '../../common/names.dart' show Names;
import '../../compiler.dart' show Compiler;
@@ -28,21 +21,16 @@
import '../../elements/elements.dart'
show
ClassElement,
- ConstructorBodyElement,
Element,
Elements,
- ElementKind,
FieldElement,
FunctionElement,
FunctionSignature,
LibraryElement,
MetadataAnnotation,
MethodElement,
- MemberElement,
Name,
- ParameterElement,
TypedefElement,
- TypeVariableElement,
VariableElement;
import '../../hash/sha1.dart' show Hasher;
import '../../io/code_output.dart';
@@ -54,25 +42,25 @@
import '../../js_backend/backend_helpers.dart' show BackendHelpers;
import '../../js_backend/js_backend.dart'
show
- CheckedModeHelper,
CompoundName,
ConstantEmitter,
- CustomElementsAnalysis,
GetterName,
JavaScriptBackend,
JavaScriptConstantCompiler,
Namer,
- RuntimeTypes,
SetterName,
- Substitution,
- TypeCheck,
- TypeChecks,
TypeVariableHandler;
import '../../universe/call_structure.dart' show CallStructure;
import '../../universe/selector.dart' show Selector;
-import '../../util/characters.dart' show $$, $A, $HASH, $PERIOD, $Z, $a, $z;
+import '../../util/characters.dart' show $$, $A, $HASH, $Z, $a, $z;
import '../../util/uri_extras.dart' show relativize;
import '../../util/util.dart' show equalElements;
+import '../constant_ordering.dart' show deepCompareConstants;
+import '../headers.dart';
+import '../js_emitter.dart' hide Emitter;
+import '../js_emitter.dart' as js_emitter show Emitter;
+import '../model.dart';
+import '../program_builder/program_builder.dart';
part 'class_builder.dart';
part 'class_emitter.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index 0a305ed..c1543de 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -8,17 +8,13 @@
import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
import 'package:js_runtime/shared/embedded_names.dart' show JsBuiltin;
+import '../closure.dart'
+ show ClosureClassElement, ClosureClassMap, ClosureFieldElement;
import '../common.dart';
import '../common/names.dart' show Identifiers;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
-import '../closure.dart'
- show
- ClosureClassElement,
- ClosureClassMap,
- ClosureFieldElement,
- CapturedVariable;
import '../core_types.dart' show CoreClasses;
import '../dart_types.dart'
show
@@ -32,17 +28,14 @@
import '../elements/elements.dart'
show
ClassElement,
- ConstructorBodyElement,
ConstructorElement,
Element,
- Elements,
ElementKind,
FieldElement,
FunctionElement,
FunctionSignature,
MetadataAnnotation,
MethodElement,
- MemberElement,
MixinApplicationElement,
ParameterElement,
TypeVariableElement;
@@ -51,17 +44,12 @@
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart'
show
- CheckedModeHelper,
- CompoundName,
- ConstantEmitter,
CustomElementsAnalysis,
- GetterName,
JavaScriptBackend,
JavaScriptConstantCompiler,
Namer,
RuntimeTypes,
RuntimeTypesEncoder,
- SetterName,
Substitution,
TypeCheck,
TypeChecks,
@@ -70,7 +58,6 @@
import '../universe/selector.dart' show Selector;
import '../universe/universe.dart' show SelectorConstraints;
import '../util/util.dart' show Setlet;
-
import 'full_emitter/emitter.dart' as full_js_emitter;
import 'lazy_emitter/emitter.dart' as lazy_js_emitter;
import 'model.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 e3f287b..64e1f79b 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
@@ -4,8 +4,7 @@
library dart2js.js_emitter.lazy_emitter;
-import 'package:js_runtime/shared/embedded_names.dart'
- show JsBuiltin, METADATA, TYPES;
+import 'package:js_runtime/shared/embedded_names.dart' show JsBuiltin;
import '../../common.dart';
import '../../compiler.dart' show Compiler;
@@ -14,12 +13,10 @@
show ClassElement, Element, FieldElement, FunctionElement;
import '../../js/js.dart' as js;
import '../../js_backend/js_backend.dart' show JavaScriptBackend, Namer;
-
import '../js_emitter.dart' show NativeEmitter;
import '../js_emitter.dart' as emitterTask show Emitter;
import '../model.dart';
import '../program_builder/program_builder.dart' show ProgramBuilder;
-
import 'model_emitter.dart';
class Emitter implements emitterTask.Emitter {
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index c7adf76..a9a6d26 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -7,9 +7,7 @@
import '../constants/values.dart' show ConstantValue;
import '../deferred_load.dart' show OutputUnit;
import '../elements/elements.dart' show Element;
-import '../js/js.dart' as js
- show Expression, Literal, Name, Statement, TokenFinalizer;
-
+import '../js/js.dart' as js show Expression, Name, Statement, TokenFinalizer;
import 'js_emitter.dart' show MetadataCollector;
class Program {
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 6377d27..78f3cda 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -35,11 +35,6 @@
BackendHelpers get helpers => backend.helpers;
- jsAst.Expression get defPropFunction {
- Element element = helpers.defineProperty;
- return emitterTask.staticFunctionAccess(element);
- }
-
/**
* Prepares native classes for emission. Returns the unneeded classes.
*
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 5d5afe6..145070f 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,6 +4,35 @@
library dart2js.js_emitter.program_builder;
+import '../../closure.dart' show ClosureFieldElement;
+import '../../common.dart';
+import '../../common/names.dart' show Names, Selectors;
+import '../../compiler.dart' show Compiler;
+import '../../constants/values.dart'
+ show ConstantValue, InterceptorConstantValue;
+import '../../core_types.dart' show CoreClasses;
+import '../../dart_types.dart' show DartType, FunctionType, TypedefType;
+import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit;
+import '../../elements/elements.dart'
+ show
+ ClassElement,
+ Element,
+ Elements,
+ FieldElement,
+ FunctionElement,
+ FunctionSignature,
+ GetterElement,
+ LibraryElement,
+ MethodElement,
+ ParameterElement,
+ TypedefElement,
+ VariableElement;
+import '../../js/js.dart' as js;
+import '../../js_backend/backend_helpers.dart' show BackendHelpers;
+import '../../js_backend/js_backend.dart'
+ show Namer, JavaScriptBackend, JavaScriptConstantCompiler, StringBackedName;
+import '../../universe/selector.dart' show Selector;
+import '../../universe/universe.dart' show Universe, SelectorConstraints;
import '../js_emitter.dart'
show
ClassStubGenerator,
@@ -17,40 +46,9 @@
TypeTestProperties;
import '../model.dart';
-import '../../closure.dart' show ClosureFieldElement;
-import '../../common.dart';
-import '../../common/names.dart' show Names, Selectors;
-import '../../compiler.dart' show Compiler;
-import '../../constants/values.dart'
- show ConstantValue, InterceptorConstantValue;
-import '../../core_types.dart' show CoreClasses;
-import '../../dart_types.dart' show DartType, FunctionType, TypedefType;
-import '../../elements/elements.dart'
- show
- ClassElement,
- Element,
- Elements,
- FieldElement,
- FunctionElement,
- FunctionSignature,
- GetterElement,
- LibraryElement,
- MethodElement,
- Name,
- ParameterElement,
- TypedefElement,
- VariableElement;
-import '../../js/js.dart' as js;
-import '../../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../../js_backend/js_backend.dart'
- show Namer, JavaScriptBackend, JavaScriptConstantCompiler, StringBackedName;
-import '../../universe/selector.dart' show Selector;
-import '../../universe/universe.dart' show Universe, SelectorConstraints;
-import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit;
-
part 'collector.dart';
-part 'registry.dart';
part 'field_visitor.dart';
+part 'registry.dart';
/// Builds a self-contained representation of the program that can then be
/// emitted more easily by the individual emitters.
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index b666bfa..d555a73 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -6,9 +6,9 @@
import 'dart:async';
-import 'common.dart';
import 'common/names.dart' show Uris;
import 'common/tasks.dart' show CompilerTask;
+import 'common.dart';
import 'compiler.dart' show Compiler;
import 'elements/elements.dart'
show
@@ -16,8 +16,7 @@
Element,
ImportElement,
ExportElement,
- LibraryElement,
- PrefixElement;
+ LibraryElement;
import 'elements/modelx.dart'
show
CompilationUnitElementX,
@@ -30,11 +29,15 @@
PrefixElementX,
SyntheticImportElement;
import 'environment.dart';
+import 'resolved_uri_translator.dart';
import 'script.dart';
import 'serialization/serialization.dart' show LibraryDeserializer;
import 'tree/tree.dart';
import 'util/util.dart' show Link, LinkBuilder;
+typedef Future<Iterable<LibraryElement>> ReuseLibrariesFunction(
+ Iterable<LibraryElement> libraries);
+
/**
* [CompilerTask] for loading libraries and setting up the import/export scopes.
*
@@ -167,6 +170,10 @@
/// Asynchronous version of [reset].
Future resetAsync(Future<bool> reuseLibrary(LibraryElement library));
+
+ /// Similar to [resetAsync] but [reuseLibrary] maps all libraries to a list
+ /// of libraries that can be reused.
+ Future<Null> resetLibraries(ReuseLibrariesFunction reuseLibraries);
}
/// Handle for creating synthesized/patch libraries during library loading.
@@ -345,7 +352,17 @@
return measure(() {
assert(currentHandler == null);
- wrapper(lib) => reuseLibrary(lib).then((reuse) => reuse ? lib : null);
+ Future<LibraryElement> wrapper(LibraryElement library) {
+ try {
+ return reuseLibrary(library)
+ .then((bool reuse) => reuse ? library : null);
+ } catch (exception, trace) {
+ reporter.onCrashInUserCode(
+ 'Uncaught exception in reuseLibrary', exception, trace);
+ rethrow;
+ }
+ }
+
List<Future<LibraryElement>> reusedLibrariesFuture =
// TODO(sigmund): make measurements separate from compiler
compiler.reuseLibraryTask.measure(
@@ -353,12 +370,32 @@
return Future
.wait(reusedLibrariesFuture)
- .then((List<LibraryElement> reusedLibraries) {
+ .then((Iterable<LibraryElement> reusedLibraries) {
resetImplementation(reusedLibraries.where((e) => e != null));
});
});
}
+ Future<Null> resetLibraries(
+ Future<Iterable<LibraryElement>> reuseLibraries(
+ Iterable<LibraryElement> libraries)) {
+ assert(currentHandler == null);
+ return compiler.reuseLibraryTask.measure(() {
+ return new Future<Iterable<LibraryElement>>(() {
+ // Wrap in Future to shield against errors in user code.
+ return reuseLibraries(libraryCanonicalUriMap.values);
+ }).catchError((exception, StackTrace trace) {
+ compiler.reportCrashInUserCode(
+ 'Uncaught exception in reuseLibraries', exception, trace);
+ throw exception; // Async rethrow.
+ }).then((Iterable<LibraryElement> reusedLibraries) {
+ measure(() {
+ resetImplementation(reusedLibraries);
+ });
+ });
+ });
+ }
+
/// Insert [library] in the internal maps. Used for compiler reuse.
void mapLibrary(LibraryElement library) {
libraryCanonicalUriMap[library.canonicalUri] = library;
@@ -1405,17 +1442,6 @@
String toString() => 'root=$rootLibrary,libraries=${loadedLibraries.keys}';
}
-/// API used by the library loader to translate internal SDK URIs into file
-/// system readable URIs.
-abstract class ResolvedUriTranslator {
- // TODO(sigmund): move here the comments from library loader.
- /// Translate the resolved [uri] in the context of [importingLibrary].
- ///
- /// Use [spannable] for error reporting.
- Uri translate(LibraryElement importingLibrary, Uri uri,
- [Spannable spannable]);
-}
-
// TODO(sigmund): remove ScriptLoader & ElementScanner. Such abstraction seems
// rather low-level. It might be more practical to split the library-loading
// task itself. The task would continue to do the work of recursively loading
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
index 745712a..9ca158b 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
@@ -18,16 +18,15 @@
import '../tokens/token.dart';
import '../tokens/token_constants.dart' as Tokens;
import '../tree/tree.dart';
-import '../util/util.dart' show Link, LinkBuilder;
import '../util/characters.dart' show $CR, $LF;
-
-import 'source_mirrors.dart';
+import '../util/util.dart' show Link;
import 'mirrors_util.dart';
+import 'source_mirrors.dart';
-part 'dart2js_library_mirror.dart';
-part 'dart2js_type_mirrors.dart';
-part 'dart2js_member_mirrors.dart';
part 'dart2js_instance_mirrors.dart';
+part 'dart2js_library_mirror.dart';
+part 'dart2js_member_mirrors.dart';
+part 'dart2js_type_mirrors.dart';
//------------------------------------------------------------------------------
// Utility types and functions for the dart2js mirror system
diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart
index 15f7c6d..a13469e 100644
--- a/pkg/compiler/lib/src/mirrors_used.dart
+++ b/pkg/compiler/lib/src/mirrors_used.dart
@@ -4,8 +4,8 @@
library dart2js.mirrors_used;
-import 'common.dart';
import 'common/tasks.dart' show CompilerTask;
+import 'common.dart';
import 'compile_time_constants.dart' show ConstantCompiler;
import 'compiler.dart' show Compiler;
import 'constants/expressions.dart';
@@ -16,7 +16,7 @@
ListConstantValue,
StringConstantValue,
TypeConstantValue;
-import 'dart_types.dart' show DartType, InterfaceType, TypeKind;
+import 'dart_types.dart' show DartType, InterfaceType;
import 'elements/elements.dart'
show
ClassElement,
@@ -27,8 +27,7 @@
ScopeContainerElement,
VariableElement;
import 'resolution/tree_elements.dart' show TreeElements;
-import 'tree/tree.dart'
- show Import, LibraryTag, NamedArgument, NewExpression, Node;
+import 'tree/tree.dart' show NamedArgument, NewExpression, Node;
/**
* Compiler task that analyzes MirrorsUsed annotations.
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index edca67c..daa6ddc 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -4,7 +4,7 @@
import '../common.dart';
import '../common/backend_api.dart' show ForeignResolver;
-import '../common/resolution.dart' show Parsing, Resolution;
+import '../common/resolution.dart' show ParsingContext, Resolution;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../core_types.dart' show CoreTypes;
@@ -28,6 +28,14 @@
static const JsObject = const SpecialType._('=Object');
int get hashCode => name.hashCode;
+
+ static SpecialType fromName(String name) {
+ if (name == '=Object') {
+ return JsObject;
+ } else {
+ throw new UnsupportedError("Unknown SpecialType '$name'.");
+ }
+ }
}
/// Description of the exception behaviour of native code.
@@ -70,6 +78,21 @@
if (this == MUST) return 'must';
return 'NativeThrowBehavior($_bits)';
}
+
+ /// Canonical list of marker values.
+ ///
+ /// Added to make [NativeThrowBehavior] enum-like.
+ static const List<NativeThrowBehavior> values = const <NativeThrowBehavior>[
+ NEVER,
+ MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS,
+ MAY,
+ MUST,
+ ];
+
+ /// Index to this marker within [values].
+ ///
+ /// Added to make [NativeThrowBehavior] enum-like.
+ int get index => values.indexOf(this);
}
/**
@@ -109,11 +132,12 @@
/// [DartType]s or [SpecialType]s instantiated by the native element.
final List typesInstantiated = [];
+ String codeTemplateText;
// If this behavior is for a JS expression, [codeTemplate] contains the
// parsed tree.
js.Template codeTemplate;
- final SideEffects sideEffects = new SideEffects.empty();
+ final SideEffects sideEffects;
NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY;
@@ -128,6 +152,10 @@
static NativeBehavior get CHANGES_OTHER => NativeBehavior._makeChangesOther();
static NativeBehavior get DEPENDS_OTHER => NativeBehavior._makeDependsOther();
+ NativeBehavior() : sideEffects = new SideEffects.empty();
+
+ NativeBehavior.internal(this.sideEffects);
+
String toString() {
return 'NativeBehavior('
'returns: ${typesReturned}'
@@ -460,7 +488,7 @@
}
static NativeBehavior ofJsCall(Send jsCall, DiagnosticReporter reporter,
- Parsing parsing, CoreTypes coreTypes, ForeignResolver resolver) {
+ ParsingContext parsing, CoreTypes coreTypes, ForeignResolver resolver) {
// The first argument of a JS-call is a string encoding various attributes
// of the code.
//
@@ -490,8 +518,8 @@
return behavior;
}
- behavior.codeTemplate =
- js.js.parseForeignJS(codeArgument.dartString.slowToString());
+ behavior.codeTemplateText = codeArgument.dartString.slowToString();
+ behavior.codeTemplate = js.js.parseForeignJS(behavior.codeTemplateText);
String specString = specArgument.dartString.slowToString();
@@ -551,7 +579,7 @@
NativeBehavior behavior,
Send jsBuiltinOrEmbeddedGlobalCall,
DiagnosticReporter reporter,
- Parsing parsing,
+ ParsingContext parsing,
CoreTypes coreTypes,
ForeignResolver resolver,
{bool isBuiltin,
@@ -619,7 +647,7 @@
static NativeBehavior ofJsBuiltinCall(
Send jsBuiltinCall,
DiagnosticReporter reporter,
- Parsing parsing,
+ ParsingContext parsing,
CoreTypes coreTypes,
ForeignResolver resolver) {
NativeBehavior behavior = new NativeBehavior();
@@ -635,7 +663,7 @@
static NativeBehavior ofJsEmbeddedGlobalCall(
Send jsEmbeddedGlobalCall,
DiagnosticReporter reporter,
- Parsing parsing,
+ ParsingContext parsing,
CoreTypes coreTypes,
ForeignResolver resolver) {
NativeBehavior behavior = new NativeBehavior();
@@ -773,7 +801,8 @@
StringConstantValue specStringConstant = fields.single;
String specString = specStringConstant.toDartString().slowToString();
for (final typeString in specString.split('|')) {
- var type = _parseType(typeString, compiler.parsing, lookup, annotation);
+ var type =
+ _parseType(typeString, compiler.parsingContext, lookup, annotation);
if (types == null) types = [];
types.add(type);
}
@@ -815,7 +844,6 @@
_escape(parameter, resolution);
}
} else {
- DartType instantiated = null;
JavaScriptBackend backend = compiler?.backend;
if (!isInterop) {
typesInstantiated.add(type);
@@ -848,8 +876,8 @@
}
}
- static dynamic _parseType(
- String typeString, Parsing parsing, lookup(name), locationNodeOrElement) {
+ static dynamic _parseType(String typeString, ParsingContext parsing,
+ lookup(name), locationNodeOrElement) {
DiagnosticReporter reporter = parsing.reporter;
if (typeString == '=Object') return SpecialType.JsObject;
if (typeString == 'dynamic') {
@@ -874,7 +902,7 @@
return const DynamicType();
}
- static _errorNode(locationNodeOrElement, Parsing parsing) {
+ static _errorNode(locationNodeOrElement, ParsingContext parsing) {
if (locationNodeOrElement is Node) return locationNodeOrElement;
return locationNodeOrElement.parseNode(parsing);
}
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 03f3fc2..c04509b 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -7,22 +7,20 @@
import '../common.dart';
import '../common/backend_api.dart' show ForeignResolver;
import '../common/registry.dart' show Registry;
-import '../common/resolution.dart' show Parsing, Resolution;
+import '../common/resolution.dart' show Resolution;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../core_types.dart' show CoreTypes;
import '../dart_types.dart';
-import '../enqueue.dart' show Enqueuer, ResolutionEnqueuer;
import '../elements/elements.dart';
-import '../elements/modelx.dart'
- show BaseClassElementX, ElementX, FunctionElementX, LibraryElementX;
+import '../elements/modelx.dart' show FunctionElementX;
+import '../enqueue.dart' show Enqueuer;
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart';
import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
import '../tokens/token.dart' show BeginGroupToken, Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN, STRING_TOKEN;
+import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
import '../tree/tree.dart';
-
import 'behavior.dart';
/**
@@ -50,8 +48,6 @@
/// Computes types instantiated due to setting a native field.
void registerFieldStore(Element field) {}
- NativeBehavior getNativeBehaviorOf(Send node) => new NativeBehavior();
-
/// Returns whether native classes are being used.
bool hasInstantiatedNativeClasses() => false;
@@ -97,10 +93,6 @@
final queue = new Queue();
bool flushing = false;
- /// Maps JS foreign calls to their computed native behavior.
- final Map<Node, NativeBehavior> nativeBehaviors =
- new Map<Node, NativeBehavior>();
-
final Enqueuer world;
final Compiler compiler;
final bool enableLiveTypeAnalysis;
@@ -468,7 +460,7 @@
if (!backend.canLibraryUseNative(element.library)) return false;
// Native method?
return reporter.withCurrentElement(element, () {
- Node node = element.parseNode(resolution.parsing);
+ Node node = element.parseNode(resolution.parsingContext);
if (node is! FunctionExpression) return false;
FunctionExpression functionExpression = node;
node = functionExpression.body;
@@ -495,8 +487,6 @@
registerNativeBehavior(NativeBehavior.ofFieldStore(field, compiler), field);
}
- NativeBehavior getNativeBehaviorOf(Send node) => nativeBehaviors[node];
-
processNativeBehavior(NativeBehavior behavior, cause) {
// TODO(ahe): Is this really a global dependency?
Registry registry = compiler.globalDependencies;
@@ -615,11 +605,12 @@
* JS('_DOMWindowImpl', 'window')
*
*/
- void registerJsCall(Send node, ForeignResolver resolver) {
+ NativeBehavior resolveJsCall(Send node, ForeignResolver resolver) {
NativeBehavior behavior = NativeBehavior.ofJsCall(
- node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+ node, reporter, compiler.parsingContext, compiler.coreTypes, resolver);
+ // TODO(johnniwinther): Move registration to the world impact application.
registerNativeBehavior(behavior, node);
- nativeBehaviors[node] = behavior;
+ return behavior;
}
/**
@@ -631,11 +622,13 @@
* JS_EMBEDDED_GLOBAL('String', 'foo')
*
*/
- void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) {
+ NativeBehavior resolveJsEmbeddedGlobalCall(
+ Send node, ForeignResolver resolver) {
NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall(
- node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+ node, reporter, compiler.parsingContext, compiler.coreTypes, resolver);
+ // TODO(johnniwinther): Move registration to the world impact application.
registerNativeBehavior(behavior, node);
- nativeBehaviors[node] = behavior;
+ return behavior;
}
/**
@@ -647,11 +640,12 @@
* JS_BUILTIN('String', 'int2string', 0)
*
*/
- void registerJsBuiltinCall(Send node, ForeignResolver resolver) {
+ NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver) {
NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall(
- node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+ node, reporter, compiler.parsingContext, compiler.coreTypes, resolver);
+ // TODO(johnniwinther): Move registration to the world impact application.
registerNativeBehavior(behavior, node);
- nativeBehaviors[node] = behavior;
+ return behavior;
}
}
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index 805196a..9a81401 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -13,24 +13,30 @@
export 'scanner.dart';
export 'ssa.dart';
+const Iterable<String> _allowedDartSchemePaths = const <String>[
+ 'async',
+ 'html',
+ 'html_common',
+ 'indexed_db',
+ 'js',
+ 'svg',
+ '_native_typed_data',
+ 'web_audio',
+ 'web_gl',
+ 'web_sql'
+];
+
bool maybeEnableNative(Compiler compiler, LibraryElement library) {
- String libraryName = library.canonicalUri.toString();
- if (library.entryCompilationUnit.script.name
- .contains('sdk/tests/compiler/dart2js_native') ||
- library.entryCompilationUnit.script.name
- .contains('sdk/tests/compiler/dart2js_extra') ||
- libraryName == 'dart:async' ||
- libraryName == 'dart:html' ||
- libraryName == 'dart:html_common' ||
- libraryName == 'dart:indexed_db' ||
- libraryName == 'dart:js' ||
- libraryName == 'dart:svg' ||
- libraryName == 'dart:_native_typed_data' ||
- libraryName == 'dart:web_audio' ||
- libraryName == 'dart:web_gl' ||
- libraryName == 'dart:web_sql' ||
- compiler.options.allowNativeExtensions) {
- return true;
+ bool allowedTestLibrary() {
+ String scriptName = library.entryCompilationUnit.script.name;
+ return scriptName.contains('sdk/tests/compiler/dart2js_native') ||
+ scriptName.contains('sdk/tests/compiler/dart2js_extra');
}
- return false;
+ bool allowedDartLibary() {
+ Uri uri = library.canonicalUri;
+ if (uri.scheme != 'dart') return false;
+ return _allowedDartSchemePaths.contains(uri.path);
+ }
+
+ return allowedTestLibrary() || allowedDartLibary();
}
diff --git a/pkg/compiler/lib/src/native/scanner.dart b/pkg/compiler/lib/src/native/scanner.dart
index f402431..f22b866 100644
--- a/pkg/compiler/lib/src/native/scanner.dart
+++ b/pkg/compiler/lib/src/native/scanner.dart
@@ -3,17 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
import '../common.dart';
-import '../parser/listener.dart' show Listener;
import '../parser/element_listener.dart' show ElementListener;
+import '../parser/listener.dart' show Listener;
import '../tokens/token.dart' show BeginGroupToken, Token;
-import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN, STRING_TOKEN;
+import '../tokens/token_constants.dart' as Tokens show STRING_TOKEN;
void checkAllowedLibrary(ElementListener listener, Token token) {
if (listener.scannerOptions.canUseNative) return;
listener.reportError(token, MessageKind.NATIVE_NOT_SUPPORTED);
}
-Token handleNativeBlockToSkip(Listener listener, Token token) {
+Token handleNativeBlockToSkip(ElementListener listener, Token token) {
checkAllowedLibrary(listener, token);
token = token.next;
if (identical(token.kind, Tokens.STRING_TOKEN)) {
diff --git a/pkg/compiler/lib/src/native/ssa.dart b/pkg/compiler/lib/src/native/ssa.dart
index 7ab20c5..f3134c3 100644
--- a/pkg/compiler/lib/src/native/ssa.dart
+++ b/pkg/compiler/lib/src/native/ssa.dart
@@ -9,7 +9,7 @@
import '../elements/elements.dart';
import '../js/js.dart' as js;
import '../js_backend/js_backend.dart';
-import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
+import '../js_emitter/js_emitter.dart' show NativeEmitter;
import '../ssa/builder.dart' show SsaBuilder;
import '../ssa/nodes.dart' show HInstruction, HForeignCode, HReturn;
import '../tree/tree.dart';
diff --git a/pkg/compiler/lib/src/parser/diet_parser_task.dart b/pkg/compiler/lib/src/parser/diet_parser_task.dart
index 6d9302e..4192143 100644
--- a/pkg/compiler/lib/src/parser/diet_parser_task.dart
+++ b/pkg/compiler/lib/src/parser/diet_parser_task.dart
@@ -5,6 +5,7 @@
library dart2js.parser.diet.task;
import '../common.dart';
+import '../common/backend_api.dart' show Backend;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../elements/elements.dart' show CompilationUnitElement;
@@ -19,23 +20,28 @@
class DietParserTask extends CompilerTask {
final ParserOptions _parserOptions;
final IdGenerator _idGenerator;
+ final Backend _backend;
+ final DiagnosticReporter _reporter;
- DietParserTask(Compiler compiler, this._parserOptions, this._idGenerator)
+ DietParserTask(Compiler compiler, this._parserOptions, this._idGenerator,
+ this._backend, this._reporter)
: super(compiler);
final String name = 'Diet Parser';
dietParse(CompilationUnitElement compilationUnit, Token tokens) {
measure(() {
- ScannerOptions scannerOptions =
- new ScannerOptions.from(compiler, compilationUnit.library);
+ ScannerOptions scannerOptions = new ScannerOptions(
+ canUseNative: _backend.canLibraryUseNative(compilationUnit.library));
ElementListener listener = new ElementListener(
- scannerOptions, compiler.reporter, compilationUnit, _idGenerator);
+ scannerOptions, _reporter, compilationUnit, _idGenerator);
PartialParser parser = new PartialParser(listener, _parserOptions);
try {
parser.parseUnit(tokens);
} on ParserError catch (_) {
- assert(invariant(compilationUnit, compiler.compilationFailed));
+ // TODO(johnniwinther): assert that the error was reported once there is
+ // a [hasErrorBeenReported] field in [DiagnosticReporter]
+ // The error should have already been reported by the parser.
}
});
}
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index b089ae5..0cd21ac 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -51,9 +51,6 @@
final bool canUseNative;
const ScannerOptions({this.canUseNative: false});
-
- ScannerOptions.from(Compiler compiler, LibraryElement libraryElement)
- : canUseNative = compiler.backend.canLibraryUseNative(libraryElement);
}
/**
@@ -368,10 +365,10 @@
pushNode(null);
}
- void endTypeVariable(Token token) {
+ void endTypeVariable(Token token, Token extendsOrSuper) {
TypeAnnotation bound = popNode();
Identifier name = popNode();
- pushNode(new TypeVariable(name, bound));
+ pushNode(new TypeVariable(name, extendsOrSuper, bound));
rejectBuiltInIdentifier(name);
}
diff --git a/pkg/compiler/lib/src/parser/listener.dart b/pkg/compiler/lib/src/parser/listener.dart
index e1e4c3c..1294bf1 100644
--- a/pkg/compiler/lib/src/parser/listener.dart
+++ b/pkg/compiler/lib/src/parser/listener.dart
@@ -301,7 +301,7 @@
void beginTypeVariable(Token token) {}
- void endTypeVariable(Token token) {}
+ void endTypeVariable(Token token, Token extendsOrSuper) {}
void beginTypeVariables(Token token) {}
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
index a13024c..b50847e 100644
--- a/pkg/compiler/lib/src/parser/member_listener.dart
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -5,13 +5,11 @@
library dart2js.parser.member_listener;
import '../common.dart';
-import '../elements/elements.dart'
- show Element, ElementKind, Elements, MetadataAnnotation;
+import '../elements/elements.dart' show Element, ElementKind, Elements;
import '../elements/modelx.dart'
show ClassElementX, ElementX, FieldElementX, VariableList;
import '../tokens/token.dart' show Token;
import '../tree/tree.dart';
-
import 'element_listener.dart' show ScannerOptions;
import 'node_listener.dart' show NodeListener;
import 'partial_elements.dart'
diff --git a/pkg/compiler/lib/src/parser/node_listener.dart b/pkg/compiler/lib/src/parser/node_listener.dart
index df288b6..9f6e18b 100644
--- a/pkg/compiler/lib/src/parser/node_listener.dart
+++ b/pkg/compiler/lib/src/parser/node_listener.dart
@@ -7,12 +7,10 @@
import '../common.dart';
import '../elements/elements.dart' show CompilationUnitElement;
import '../native/native.dart' as native;
-import '../tokens/precedence_constants.dart' as Precedence
- show BAD_INPUT_INFO, EOF_INFO, INDEX_INFO;
+import '../tokens/precedence_constants.dart' as Precedence show INDEX_INFO;
import '../tokens/token.dart' show ErrorToken, StringToken, Token;
import '../tree/tree.dart';
import '../util/util.dart' show Link;
-
import 'element_listener.dart' show ElementListener, ScannerOptions;
import 'partial_elements.dart' show PartialFunctionElement;
@@ -566,6 +564,7 @@
void handleFunctionTypedFormalParameter(Token endToken) {
NodeList formals = popNode();
+ popNode(); // typeVariables
Identifier name = popNode();
TypeAnnotation returnType = popNode();
pushNode(null); // Signal "no type" to endFormalParameter.
@@ -755,6 +754,7 @@
Statement body = popNode();
AsyncModifier asyncModifier = popNode();
NodeList formals = popNode();
+ popNode(); // typeVariables
pushNode(new FunctionExpression(
null, formals, body, null, Modifiers.EMPTY, null, null, asyncModifier));
}
diff --git a/pkg/compiler/lib/src/parser/parser.dart b/pkg/compiler/lib/src/parser/parser.dart
index a584afb..821fcad 100644
--- a/pkg/compiler/lib/src/parser/parser.dart
+++ b/pkg/compiler/lib/src/parser/parser.dart
@@ -15,7 +15,6 @@
CASCADE_PRECEDENCE,
EQUALITY_PRECEDENCE,
GT_INFO,
- GT_GT_INFO,
IS_INFO,
MINUS_MINUS_INFO,
OPEN_PAREN_INFO,
@@ -105,9 +104,9 @@
final bool enableGenericMethodSyntax;
Parser(this.listener, ParserOptions parserOptions,
- {this.asyncAwaitKeywordsEnabled: false}) :
- parserOptions = parserOptions,
- enableGenericMethodSyntax = parserOptions.enableGenericMethodSyntax;
+ {this.asyncAwaitKeywordsEnabled: false})
+ : parserOptions = parserOptions,
+ enableGenericMethodSyntax = parserOptions.enableGenericMethodSyntax;
Token parseUnit(Token token) {
listener.beginCompilationUnit(token);
@@ -461,6 +460,11 @@
}
token = parseIdentifier(token);
if (optional('(', token)) {
+ listener.handleNoTypeVariables(token);
+ token = parseFormalParameters(token);
+ listener.handleFunctionTypedFormalParameter(token);
+ } else if (enableGenericMethodSyntax && optional('<', token)) {
+ token = parseTypeVariablesOpt(token);
token = parseFormalParameters(token);
listener.handleFunctionTypedFormalParameter(token);
}
@@ -765,12 +769,15 @@
Token parseTypeVariable(Token token) {
listener.beginTypeVariable(token);
token = parseIdentifier(token);
- if (optional('extends', token)) {
+ Token extendsOrSuper = null;
+ if (optional('extends', token) ||
+ (enableGenericMethodSyntax && optional('super', token))) {
+ extendsOrSuper = token;
token = parseType(token.next);
} else {
listener.handleNoType(token);
}
- listener.endTypeVariable(token);
+ listener.endTypeVariable(token, extendsOrSuper);
return token;
}
@@ -1843,15 +1850,37 @@
// We are looking at "type identifier '('".
BeginGroupToken beginParen = afterId;
Token endParen = beginParen.endGroup;
+ // TODO(eernst): Check for NPE as described in issue 26252.
Token afterParens = endParen.next;
if (optional('{', afterParens) ||
optional('=>', afterParens) ||
optional('async', afterParens) ||
optional('sync', afterParens)) {
// We are looking at "type identifier '(' ... ')'" followed
- // by '=>' or '{'.
+ // by '{', '=>', 'async', or 'sync'.
return parseFunctionDeclaration(token);
}
+ } else if (enableGenericMethodSyntax &&
+ identical(afterIdKind, LT_TOKEN)) {
+ // We are looking at "type identifier '<'".
+ BeginGroupToken beginAngle = afterId;
+ Token endAngle = beginAngle.endGroup;
+ if (endAngle != null &&
+ identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
+ BeginGroupToken beginParen = endAngle.next;
+ Token endParen = beginParen.endGroup;
+ if (endParen != null) {
+ Token afterParens = endParen.next;
+ if (optional('{', afterParens) ||
+ optional('=>', afterParens) ||
+ optional('async', afterParens) ||
+ optional('sync', afterParens)) {
+ // We are looking at "type identifier '<' ... '>' '(' ... ')'"
+ // followed by '{', '=>', 'async', or 'sync'.
+ return parseFunctionDeclaration(token);
+ }
+ }
+ }
}
// Fall-through to expression statement.
} else {
@@ -1859,6 +1888,7 @@
return parseLabeledStatement(token);
} else if (optional('(', token.next)) {
BeginGroupToken begin = token.next;
+ // TODO(eernst): Check for NPE as described in issue 26252.
String afterParens = begin.endGroup.next.stringValue;
if (identical(afterParens, '{') ||
identical(afterParens, '=>') ||
@@ -1866,6 +1896,24 @@
identical(afterParens, 'sync')) {
return parseFunctionDeclaration(token);
}
+ } else if (enableGenericMethodSyntax && optional('<', token.next)) {
+ BeginGroupToken beginAngle = token.next;
+ Token endAngle = beginAngle.endGroup;
+ if (endAngle != null &&
+ identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
+ BeginGroupToken beginParen = endAngle.next;
+ Token endParen = beginParen.endGroup;
+ if (endParen != null) {
+ String afterParens = endParen.next.stringValue;
+ if (identical(afterParens, '{') ||
+ identical(afterParens, '=>') ||
+ identical(afterParens, 'async') ||
+ identical(afterParens, 'sync')) {
+ return parseFunctionDeclaration(token);
+ }
+ }
+ }
+ // Fall through to expression statement.
}
}
return parseExpressionStatement(token);
@@ -2133,11 +2181,14 @@
}
} else if (kind == OPEN_PAREN_TOKEN) {
return parseParenthesizedExpressionOrFunctionLiteral(token);
- } else if ((kind == LT_TOKEN) ||
- (kind == OPEN_SQUARE_BRACKET_TOKEN) ||
- (kind == OPEN_CURLY_BRACKET_TOKEN) ||
- token.stringValue == '[]') {
- return parseLiteralListOrMap(token);
+ } else if (kind == OPEN_SQUARE_BRACKET_TOKEN || token.stringValue == '[]') {
+ listener.handleNoTypeArguments(token);
+ return parseLiteralListSuffix(token, null);
+ } else if (kind == OPEN_CURLY_BRACKET_TOKEN) {
+ listener.handleNoTypeArguments(token);
+ return parseLiteralMapSuffix(token, null);
+ } else if (kind == LT_TOKEN) {
+ return parseLiteralListOrMapOrFunction(token, null);
} else {
return listener.expectedExpression(token);
}
@@ -2145,6 +2196,7 @@
Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
BeginGroupToken beginGroup = token;
+ // TODO(eernst): Check for NPE as described in issue 26252.
Token nextToken = beginGroup.endGroup.next;
int kind = nextToken.kind;
if (mayParseFunctionExpressions &&
@@ -2152,6 +2204,7 @@
identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
(identical(kind, KEYWORD_TOKEN) &&
(nextToken.value == 'async' || nextToken.value == 'sync')))) {
+ listener.handleNoTypeVariables(token);
return parseUnnamedFunction(token);
} else {
bool old = mayParseFunctionExpressions;
@@ -2201,30 +2254,16 @@
return token;
}
- Token parseLiteralListOrMap(Token token) {
- Token constKeyword = null;
- if (optional('const', token)) {
- constKeyword = token;
- token = token.next;
- }
- token = parseTypeArgumentsOpt(token);
+ /// '[' (expressionList ','?)? ']'.
+ ///
+ /// Provide [constKeyword] if preceded by 'const', null if not.
+ /// This is a suffix parser because it is assumed that type arguments have
+ /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
+ Token parseLiteralListSuffix(Token token, Token constKeyword) {
+ assert(optional('[', token) || optional('[]', token));
Token beginToken = token;
int count = 0;
- if (optional('{', token)) {
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- do {
- if (optional('}', token.next)) {
- token = token.next;
- break;
- }
- token = parseMapLiteralEntry(token.next);
- ++count;
- } while (optional(',', token));
- mayParseFunctionExpressions = old;
- listener.handleLiteralMap(count, beginToken, constKeyword, token);
- return expect('}', token);
- } else if (optional('[', token)) {
+ if (optional('[', token)) {
bool old = mayParseFunctionExpressions;
mayParseFunctionExpressions = true;
do {
@@ -2238,10 +2277,83 @@
mayParseFunctionExpressions = old;
listener.handleLiteralList(count, beginToken, constKeyword, token);
return expect(']', token);
- } else if (optional('[]', token)) {
- listener.handleLiteralList(0, token, constKeyword, token);
- return token.next;
+ }
+ // Looking at '[]'.
+ listener.handleLiteralList(0, token, constKeyword, token);
+ return token.next;
+ }
+
+ /// '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'.
+ ///
+ /// Provide token for [constKeyword] if preceded by 'const', null if not.
+ /// This is a suffix parser because it is assumed that type arguments have
+ /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
+ Token parseLiteralMapSuffix(Token token, Token constKeyword) {
+ assert(optional('{', token));
+ Token beginToken = token;
+ int count = 0;
+ bool old = mayParseFunctionExpressions;
+ mayParseFunctionExpressions = true;
+ do {
+ if (optional('}', token.next)) {
+ token = token.next;
+ break;
+ }
+ token = parseMapLiteralEntry(token.next);
+ ++count;
+ } while (optional(',', token));
+ mayParseFunctionExpressions = old;
+ listener.handleLiteralMap(count, beginToken, constKeyword, token);
+ return expect('}', token);
+ }
+
+ /// formalParameterList functionBody.
+ ///
+ /// This is a suffix parser because it is assumed that type arguments have
+ /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
+ Token parseLiteralFunctionSuffix(Token token) {
+ assert(optional('(', token));
+ BeginGroupToken beginGroup = token;
+ if (beginGroup.endGroup != null) {
+ Token nextToken = beginGroup.endGroup.next;
+ int kind = nextToken.kind;
+ if (identical(kind, FUNCTION_TOKEN) ||
+ identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
+ (identical(kind, KEYWORD_TOKEN) &&
+ (nextToken.value == 'async' || nextToken.value == 'sync'))) {
+ return parseUnnamedFunction(token);
+ }
+ // Fall through.
+ }
+ listener.unexpected(token);
+ return null;
+ }
+
+ /// genericListLiteral | genericMapLiteral | genericFunctionLiteral.
+ ///
+ /// Where
+ /// genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']'
+ /// genericMapLiteral ::=
+ /// typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
+ /// genericFunctionLiteral ::=
+ /// typeParameters formalParameterList functionBody
+ /// Provide token for [constKeyword] if preceded by 'const', null if not.
+ Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) {
+ assert(optional('<', token));
+ BeginGroupToken begin = token;
+ if (enableGenericMethodSyntax &&
+ constKeyword == null &&
+ begin.endGroup != null &&
+ identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) {
+ token = parseTypeVariablesOpt(token);
+ return parseLiteralFunctionSuffix(token);
} else {
+ token = parseTypeArgumentsOpt(token);
+ if (optional('{', token)) {
+ return parseLiteralMapSuffix(token, constKeyword);
+ } else if ((optional('[', token)) || (optional('[]', token))) {
+ return parseLiteralListSuffix(token, constKeyword);
+ }
listener.unexpected(token);
return null;
}
@@ -2273,8 +2385,14 @@
}
bool isFunctionDeclaration(Token token) {
+ if (enableGenericMethodSyntax && optional('<', token)) {
+ BeginGroupToken begin = token;
+ if (begin.endGroup == null) return false;
+ token = begin.endGroup.next;
+ }
if (optional('(', token)) {
BeginGroupToken begin = token;
+ // TODO(eernst): Check for NPE as described in issue 26252.
String afterParens = begin.endGroup.next.stringValue;
if (identical(afterParens, '{') ||
identical(afterParens, '=>') ||
@@ -2309,11 +2427,16 @@
Token constKeyword = token;
token = expect('const', token);
final String value = token.stringValue;
- if ((identical(value, '<')) ||
- (identical(value, '[')) ||
- (identical(value, '[]')) ||
- (identical(value, '{'))) {
- return parseLiteralListOrMap(constKeyword);
+ if ((identical(value, '[')) || (identical(value, '[]'))) {
+ listener.handleNoTypeArguments(token);
+ return parseLiteralListSuffix(token, constKeyword);
+ }
+ if (identical(value, '{')) {
+ listener.handleNoTypeArguments(token);
+ return parseLiteralMapSuffix(token, constKeyword);
+ }
+ if (identical(value, '<')) {
+ return parseLiteralListOrMapOrFunction(token, constKeyword);
}
token = parseConstructorReference(token);
token = parseRequiredArguments(token);
diff --git a/pkg/compiler/lib/src/parser/parser_task.dart b/pkg/compiler/lib/src/parser/parser_task.dart
index 471ebf6..6470d1f 100644
--- a/pkg/compiler/lib/src/parser/parser_task.dart
+++ b/pkg/compiler/lib/src/parser/parser_task.dart
@@ -25,7 +25,7 @@
String get name => 'Parser';
Node parse(ElementX element) {
- return measure(() => element.parseNode(compiler.parsing));
+ return measure(() => element.parseNode(compiler.parsingContext));
}
Node parseCompilationUnit(Token token) {
diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart
index a99ba64..8e74bf3 100644
--- a/pkg/compiler/lib/src/parser/partial_elements.dart
+++ b/pkg/compiler/lib/src/parser/partial_elements.dart
@@ -5,18 +5,15 @@
library dart2js.parser.partial_elements;
import '../common.dart';
-import '../common/resolution.dart' show Parsing, Resolution;
+import '../common/resolution.dart' show ParsingContext, Resolution;
import '../dart_types.dart' show DynamicType;
import '../elements/elements.dart'
show
CompilationUnitElement,
- ConstructorElement,
Element,
ElementKind,
GetterElement,
- LibraryElement,
MetadataAnnotation,
- MethodElement,
SetterElement,
STATE_NOT_STARTED,
STATE_DONE;
@@ -27,7 +24,6 @@
ConstructorElementX,
DeclarationSite,
ElementX,
- FieldElementX,
GetterElementX,
MetadataAnnotationX,
MethodElementX,
@@ -35,24 +31,14 @@
TypedefElementX,
VariableList;
import '../elements/visitor.dart' show ElementVisitor;
-import '../tokens/token.dart'
- show
- BadInputToken,
- BeginGroupToken,
- ErrorToken,
- KeywordToken,
- StringToken,
- Token,
- UnmatchedToken,
- UnterminatedToken;
+import '../tokens/token.dart' show Token;
import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
import '../tree/tree.dart';
-
import 'class_element_parser.dart' show ClassElementParser;
-import 'parser.dart' show Parser;
import 'listener.dart' show ParserError;
import 'member_listener.dart' show MemberListener;
import 'node_listener.dart' show NodeListener;
+import 'parser.dart' show Parser;
abstract class PartialElement implements DeclarationSite {
Token beginToken;
@@ -97,7 +83,7 @@
return cachedNode;
}
- FunctionExpression parseNode(Parsing parsing) {
+ FunctionExpression parseNode(ParsingContext parsing) {
if (cachedNode != null) return cachedNode;
parseFunction(Parser p) {
if (isClassMember && modifiers.isFactory) {
@@ -240,7 +226,7 @@
super.hasParseError = hasParseError;
}
- VariableDefinitions parseNode(Element element, Parsing parsing) {
+ VariableDefinitions parseNode(Element element, ParsingContext parsing) {
if (definitions != null) return definitions;
DiagnosticReporter reporter = parsing.reporter;
reporter.withCurrentElement(element, () {
@@ -265,7 +251,7 @@
computeType(Element element, Resolution resolution) {
if (type != null) return type;
// TODO(johnniwinther): Compute this in the resolver.
- VariableDefinitions node = parseNode(element, resolution.parsing);
+ VariableDefinitions node = parseNode(element, resolution.parsingContext);
if (node.type != null) {
type = resolution.reporter.withCurrentElement(element, () {
return resolution.resolveTypeAnnotation(element, node.type);
@@ -288,7 +274,7 @@
Token get token => beginToken;
- Node parseNode(Parsing parsing) {
+ Node parseNode(ParsingContext parsing) {
if (cachedNode != null) return cachedNode;
cachedNode = parse(parsing, this, declarationSite,
(p) => p.parseTopLevelDeclaration(token));
@@ -329,7 +315,7 @@
throw new UnsupportedError("endToken=");
}
- Node parseNode(Parsing parsing) {
+ Node parseNode(ParsingContext parsing) {
if (cachedNode != null) return cachedNode;
var metadata = parse(parsing, annotatedElement, declarationSite,
(p) => p.parseMetadata(beginToken));
@@ -380,7 +366,7 @@
return cachedNode;
}
- ClassNode parseNode(Parsing parsing) {
+ ClassNode parseNode(ParsingContext parsing) {
if (cachedNode != null) return cachedNode;
DiagnosticReporter reporter = parsing.reporter;
reporter.withCurrentElement(this, () {
@@ -440,7 +426,7 @@
}
}
-Node parse(Parsing parsing, ElementX element, PartialElement partial,
+Node parse(ParsingContext parsing, ElementX element, PartialElement partial,
doParse(Parser parser)) {
DiagnosticReporter reporter = parsing.reporter;
return parsing.measure(() {
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 0e9943d..9baaeb3 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -116,10 +116,10 @@
import 'dart:async';
-import 'constants/values.dart' show ConstantValue;
+import 'common/tasks.dart' show CompilerTask;
import 'common.dart';
import 'compiler.dart' show Compiler;
-import 'common/tasks.dart' show CompilerTask;
+import 'constants/values.dart' show ConstantValue;
import 'dart_types.dart' show DartType;
import 'elements/elements.dart';
import 'elements/modelx.dart'
@@ -128,18 +128,17 @@
ClassElementX,
GetterElementX,
LibraryElementX,
- MetadataAnnotationX,
SetterElementX;
import 'id_generator.dart';
import 'js_backend/js_backend.dart' show JavaScriptBackend;
import 'library_loader.dart' show LibraryLoader;
import 'options.dart' show ParserOptions;
-import 'parser/listener.dart' show Listener, ParserError;
import 'parser/element_listener.dart' show ElementListener;
+import 'parser/listener.dart' show Listener, ParserError;
import 'parser/member_listener.dart' show MemberListener;
+import 'parser/parser.dart' show Parser;
import 'parser/partial_elements.dart' show PartialClassElement;
import 'parser/partial_parser.dart' show PartialParser;
-import 'parser/parser.dart' show Parser;
import 'scanner/scanner.dart' show Scanner;
import 'script.dart';
import 'tokens/token.dart' show StringToken, Token;
@@ -177,8 +176,8 @@
// TODO(johnniwinther): Test that parts and exports are handled correctly.
Script script = compilationUnit.script;
Token tokens = new Scanner(script.file).tokenize();
- Listener patchListener =
- new PatchElementListener(compiler, compilationUnit, compiler);
+ Listener patchListener = new PatchElementListener(
+ compiler, compilationUnit, compiler.idGenerator);
try {
new PartialParser(patchListener, parserOptions).parseUnit(tokens);
} on ParserError catch (e) {
@@ -217,7 +216,7 @@
PatchMemberListener(Compiler compiler, ClassElement enclosingClass)
: this.compiler = compiler,
- super(compiler.parsing.getScannerOptionsFor(enclosingClass),
+ super(compiler.parsingContext.getScannerOptionsFor(enclosingClass),
compiler.reporter, enclosingClass);
@override
@@ -262,7 +261,7 @@
PatchElementListener(Compiler compiler, CompilationUnitElement patchElement,
IdGenerator idGenerator)
: this.compiler = compiler,
- super(compiler.parsing.getScannerOptionsFor(patchElement),
+ super(compiler.parsingContext.getScannerOptionsFor(patchElement),
compiler.reporter, patchElement, idGenerator);
@override
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 25893e2..adaa177 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -211,7 +211,11 @@
FunctionElement constructor =
new SynthesizedConstructorElementX.forDefault(superMember, element);
if (superMember.isMalformed) {
- compiler.elementsWithCompileTimeErrors.add(constructor);
+ ErroneousElement erroneousElement = superMember;
+ compiler.registerCompiletimeError(constructor,
+ reporter.createMessage(node,
+ erroneousElement.messageKind,
+ erroneousElement.messageArguments));
}
element.setDefaultConstructor(constructor, reporter);
}
@@ -299,8 +303,11 @@
String superName = supertype.name;
String mixinName = mixinType.name;
MixinApplicationElementX mixinApplication =
- new UnnamedMixinApplicationElementX("${superName}+${mixinName}",
- element.compilationUnit, compiler.getNextFreeId(), node);
+ new UnnamedMixinApplicationElementX(
+ "${superName}+${mixinName}",
+ element.compilationUnit,
+ compiler.idGenerator.getNextFreeId(),
+ node);
// Create synthetic type variables for the mixin application.
List<DartType> typeVariables = <DartType>[];
int index = 0;
@@ -352,7 +359,7 @@
void doApplyMixinTo(MixinApplicationElementX mixinApplication,
DartType supertype, DartType mixinType) {
- Node node = mixinApplication.parseNode(resolution.parsing);
+ Node node = mixinApplication.parseNode(resolution.parsingContext);
if (mixinApplication.supertype != null) {
// [supertype] is not null if there was a cycle.
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index eb993bd..6a06749 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -18,8 +18,7 @@
MemberElement,
MemberSignature,
MixinApplicationElement,
- Name,
- PublicName;
+ Name;
import '../util/util.dart';
part 'member_impl.dart';
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 9e40cff..0f9f099 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -77,7 +77,7 @@
if (initialized.containsKey(field)) {
reportDuplicateInitializerError(field, init, initialized[field]);
} else if (field.isFinal) {
- field.parseNode(visitor.resolution.parsing);
+ field.parseNode(visitor.resolution.parsingContext);
Expression initializer = field.initializer;
if (initializer != null) {
reportDuplicateInitializerError(
@@ -171,7 +171,6 @@
ConstructorElement foundConstructor =
findConstructor(constructor.library, lookupTarget, constructorName);
- final bool isImplicitSuperCall = false;
final String className = lookupTarget.name;
CallStructure callStructure = argumentsResult.callStructure;
ConstructorElement calledConstructor = verifyThatConstructorMatchesCall(
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index 93fb9ec..6b0acfa 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -171,6 +171,29 @@
}
}
+/// This class generates the model for an enum class.
+///
+/// For instance
+///
+/// enum A { b, c, }
+///
+/// is modelled as
+///
+/// class A {
+/// final int index;
+///
+/// const A(this.index);
+///
+/// String toString() {
+/// return const <int, A>{0: 'A.b', 1: 'A.c'}[index];
+/// }
+///
+/// static const A b = const A(0);
+/// static const A c = const A(1);
+///
+/// static const List<A> values = const <A>[b, c];
+/// }
+///
// TODO(johnniwinther): Avoid creating synthesized ASTs for enums when SSA is
// removed.
class EnumCreator {
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index bcd4495..e349185 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -23,31 +23,28 @@
JumpTargetX,
LocalFunctionElementX,
LocalParameterElementX,
- LocalVariableElementX,
MethodElementX,
ParameterElementX,
VariableElementX,
VariableList;
import '../tokens/token.dart' show isUserDefinableOperator;
import '../tree/tree.dart';
-import '../util/util.dart' show Link;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
-
+import '../util/util.dart' show Link;
import 'access_semantics.dart';
import 'class_members.dart' show MembersCreator;
-import 'operators.dart';
-import 'send_structure.dart';
-
import 'constructors.dart'
show ConstructorResolver, ConstructorResult, ConstructorResultKind;
import 'label_scope.dart' show StatementScope;
+import 'operators.dart';
import 'registry.dart' show ResolutionRegistry;
import 'resolution.dart' show ResolverTask;
import 'resolution_common.dart' show MappingVisitor;
import 'resolution_result.dart';
import 'scope.dart' show BlockScope, MethodScope, Scope;
+import 'send_structure.dart';
import 'signatures.dart' show SignatureResolver;
import 'variables.dart' show VariableDefinitionsVisitor;
@@ -391,7 +388,7 @@
}
FunctionElement resolveConstructorRedirection(FunctionElementX constructor) {
- FunctionExpression node = constructor.parseNode(resolution.parsing);
+ FunctionExpression node = constructor.parseNode(resolution.parsingContext);
// A synthetic constructor does not have a node.
if (node == null) return null;
@@ -3343,7 +3340,6 @@
/// `a++` or `a += b` where [semantics] describe `a`.
ResolutionResult handleUpdate(
SendSet node, Name name, AccessSemantics semantics) {
- SendStructure sendStructure;
String operatorText = node.assignmentOperator.source;
Selector getterSelector = new Selector.getter(name);
Selector setterSelector = new Selector.setter(name);
@@ -3568,7 +3564,6 @@
ConstructorElement redirectionTarget = result.element;
constructor.immediateRedirectionTarget = redirectionTarget;
- Node constructorReference = node.constructorReference;
if (result.isDeferred) {
constructor.redirectionDeferredPrefix = result.prefix;
}
@@ -3772,7 +3767,6 @@
DartType type = result.type;
ConstructorAccessKind kind;
- NewStructure newStructure;
bool isInvalid = false;
switch (result.kind) {
case ConstructorResultKind.GENERATIVE:
diff --git a/pkg/compiler/lib/src/resolution/operators.dart b/pkg/compiler/lib/src/resolution/operators.dart
index 06fd468..499192f 100644
--- a/pkg/compiler/lib/src/resolution/operators.dart
+++ b/pkg/compiler/lib/src/resolution/operators.dart
@@ -430,19 +430,32 @@
static AssignmentOperator fromKind(AssignmentOperatorKind kind) {
switch (kind) {
- case AssignmentOperatorKind.ASSIGN: return ASSIGN;
- case AssignmentOperatorKind.IF_NULL: return IF_NULL;
- case AssignmentOperatorKind.ADD: return ADD;
- case AssignmentOperatorKind.SUB: return SUB;
- case AssignmentOperatorKind.MUL: return MUL;
- case AssignmentOperatorKind.DIV: return DIV;
- case AssignmentOperatorKind.IDIV: return IDIV;
- case AssignmentOperatorKind.MOD: return MOD;
- case AssignmentOperatorKind.SHL: return SHL;
- case AssignmentOperatorKind.SHR: return SHR;
- case AssignmentOperatorKind.AND: return AND;
- case AssignmentOperatorKind.OR: return OR;
- case AssignmentOperatorKind.XOR: return XOR;
+ case AssignmentOperatorKind.ASSIGN:
+ return ASSIGN;
+ case AssignmentOperatorKind.IF_NULL:
+ return IF_NULL;
+ case AssignmentOperatorKind.ADD:
+ return ADD;
+ case AssignmentOperatorKind.SUB:
+ return SUB;
+ case AssignmentOperatorKind.MUL:
+ return MUL;
+ case AssignmentOperatorKind.DIV:
+ return DIV;
+ case AssignmentOperatorKind.IDIV:
+ return IDIV;
+ case AssignmentOperatorKind.MOD:
+ return MOD;
+ case AssignmentOperatorKind.SHL:
+ return SHL;
+ case AssignmentOperatorKind.SHR:
+ return SHR;
+ case AssignmentOperatorKind.AND:
+ return AND;
+ case AssignmentOperatorKind.OR:
+ return OR;
+ case AssignmentOperatorKind.XOR:
+ return XOR;
}
}
}
@@ -481,8 +494,10 @@
static IncDecOperator fromKind(IncDecOperatorKind kind) {
switch (kind) {
- case IncDecOperatorKind.INC: return INC;
- case IncDecOperatorKind.DEC: return DEC;
+ case IncDecOperatorKind.INC:
+ return INC;
+ case IncDecOperatorKind.DEC:
+ return DEC;
}
}
}
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index ed6db6c..0301e8c 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -20,7 +20,7 @@
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
-import '../universe/world_impact.dart' show WorldImpactBuilder;
+import '../universe/world_impact.dart' show WorldImpact, WorldImpactBuilder;
import '../util/enumset.dart' show EnumSet;
import '../world.dart' show World;
@@ -104,7 +104,39 @@
: const <ConstantExpression>[];
}
- String toString() => '_ResolutionWorldImpact($name)';
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write('_ResolutionWorldImpact($name)');
+ WorldImpact.printOn(sb, this);
+ if (_features != null) {
+ sb.write('\n features:');
+ for (Feature feature in _features.iterable(Feature.values)) {
+ sb.write('\n $feature');
+ }
+ }
+ if (_mapLiterals != null) {
+ sb.write('\n map-literals:');
+ for (MapLiteralUse use in _mapLiterals) {
+ sb.write('\n $use');
+ }
+ }
+ if (_listLiterals != null) {
+ sb.write('\n list-literals:');
+ for (ListLiteralUse use in _listLiterals) {
+ sb.write('\n $use');
+ }
+ }
+ if (_constantLiterals != null) {
+ sb.write('\n const-literals:');
+ for (ConstantExpression constant in _constantLiterals) {
+ sb.write('\n ${constant.getText()}');
+ }
+ }
+ if (_constSymbolNames != null) {
+ sb.write('\n const-symbol-names: $_constSymbolNames');
+ }
+ return sb.toString();
+ }
}
/// [ResolutionRegistry] collects all resolution information. It stores node
@@ -324,8 +356,11 @@
void registerForeignCall(Node node, Element element,
CallStructure callStructure, ResolverVisitor visitor) {
- backend.registerForeignCall(node, element, callStructure,
+ var nativeData = backend.resolveForeignCall(node, element, callStructure,
new ForeignResolutionResolver(visitor, this));
+ if (nativeData != null) {
+ mapping.registerNativeData(node, nativeData);
+ }
}
void registerDynamicUse(DynamicUse dynamicUse) {
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 7caced4..58d038b 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -9,10 +9,10 @@
import '../common.dart';
import '../common/names.dart' show Identifiers;
import '../common/resolution.dart'
- show Feature, Parsing, Resolution, ResolutionImpact;
-import '../common/tasks.dart' show CompilerTask, DeferredAction;
-import '../compiler.dart' show Compiler;
+ show Feature, ParsingContext, Resolution, ResolutionImpact;
+import '../common/tasks.dart' show CompilerTask;
import '../compile_time_constants.dart' show ConstantCompiler;
+import '../compiler.dart' show Compiler;
import '../constants/expressions.dart'
show
ConstantExpression,
@@ -47,8 +47,7 @@
import '../universe/call_structure.dart' show CallStructure;
import '../universe/use.dart' show StaticUse, TypeUse;
import '../universe/world_impact.dart' show WorldImpact;
-import '../util/util.dart' show Link, LinkBuilder, Setlet;
-
+import '../util/util.dart' show Link, Setlet;
import 'class_hierarchy.dart';
import 'class_members.dart' show MembersCreator;
import 'constructors.dart';
@@ -67,7 +66,7 @@
Resolution get resolution => compiler.resolution;
- Parsing get parsing => compiler.parsing;
+ ParsingContext get parsingContext => compiler.parsingContext;
CoreClasses get coreClasses => compiler.coreClasses;
@@ -312,7 +311,7 @@
return const ResolutionImpact();
}
} else {
- element.parseNode(resolution.parsing);
+ element.parseNode(resolution.parsingContext);
element.computeType(resolution);
FunctionElementX implementation = element;
if (element.isExternal) {
@@ -337,7 +336,7 @@
}
WorldImpact resolveField(FieldElementX element) {
- VariableDefinitions tree = element.parseNode(parsing);
+ VariableDefinitions tree = element.parseNode(parsingContext);
if (element.modifiers.isStatic && element.isTopLevel) {
reporter.reportErrorMessage(element.modifiers.getStatic(),
MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
@@ -509,7 +508,7 @@
reporter.withCurrentElement(cls, () {
// TODO(ahe): Cache the node in cls.
cls
- .parseNode(parsing)
+ .parseNode(parsingContext)
.accept(new ClassSupertypeResolver(compiler, cls));
if (cls.supertypeLoadState != STATE_DONE) {
cls.supertypeLoadState = STATE_DONE;
@@ -598,7 +597,7 @@
() => measure(() {
assert(element.resolutionState == STATE_NOT_STARTED);
element.resolutionState = STATE_STARTED;
- Node tree = element.parseNode(parsing);
+ Node tree = element.parseNode(parsingContext);
loadSupertypes(element, tree);
ClassResolverVisitor visitor =
@@ -726,18 +725,19 @@
// TODO(johnniwinther): Obtain the [TreeElements] for [member]
// differently.
if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
- checkMixinSuperUses(
- member.resolvedAst.elements, mixinApplication, mixin);
+ if (member.resolvedAst.kind == ResolvedAstKind.PARSED) {
+ checkMixinSuperUses(
+ member.resolvedAst.elements, mixinApplication, mixin);
+ }
}
}
});
}
- void checkMixinSuperUses(TreeElements resolutionTree,
+ void checkMixinSuperUses(TreeElements elements,
MixinApplicationElement mixinApplication, ClassElement mixin) {
// TODO(johnniwinther): Avoid the use of [TreeElements] here.
- if (resolutionTree == null) return;
- Iterable<SourceSpan> superUses = resolutionTree.superUses;
+ Iterable<SourceSpan> superUses = elements.superUses;
if (superUses.isEmpty) return;
DiagnosticMessage error = reporter.createMessage(mixinApplication,
MessageKind.ILLEGAL_MIXIN_WITH_SUPER, {'className': mixin.name});
@@ -965,13 +965,13 @@
FunctionSignature resolveSignature(FunctionElementX element) {
MessageKind defaultValuesError = null;
if (element.isFactoryConstructor) {
- FunctionExpression body = element.parseNode(parsing);
+ FunctionExpression body = element.parseNode(parsingContext);
if (body.isRedirectingFactory) {
defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT;
}
}
return reporter.withCurrentElement(element, () {
- FunctionExpression node = element.parseNode(parsing);
+ FunctionExpression node = element.parseNode(parsingContext);
return measure(() => SignatureResolver.analyze(
compiler,
node.parameters,
@@ -993,7 +993,7 @@
return measure(() {
assert(element.resolutionState == STATE_NOT_STARTED);
element.resolutionState = STATE_STARTED;
- Typedef node = element.parseNode(parsing);
+ Typedef node = element.parseNode(parsingContext);
TypedefResolverVisitor visitor =
new TypedefResolverVisitor(compiler, element, registry);
visitor.visit(node);
@@ -1011,7 +1011,7 @@
assert(annotation.resolutionState == STATE_NOT_STARTED);
annotation.resolutionState = STATE_STARTED;
- Node node = annotation.parseNode(parsing);
+ Node node = annotation.parseNode(parsingContext);
Element annotatedElement = annotation.annotatedElement;
AnalyzableElement context = annotatedElement.analyzableElement;
ClassElement classElement = annotatedElement.enclosingClass;
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 7b166d9..36ea970 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -13,14 +13,12 @@
ErroneousFieldElementX,
ErroneousInitializingFormalElementX,
FormalElementX,
- FunctionElementX,
FunctionSignatureX,
InitializingFormalElementX,
LocalParameterElementX;
import '../tree/tree.dart';
import '../universe/use.dart' show TypeUse;
import '../util/util.dart' show Link, LinkBuilder;
-
import 'members.dart' show ResolverVisitor;
import 'registry.dart' show ResolutionRegistry;
import 'resolution_common.dart' show MappingVisitor;
diff --git a/pkg/compiler/lib/src/resolution/tree_elements.dart b/pkg/compiler/lib/src/resolution/tree_elements.dart
index 1d1ddce..9c60745 100644
--- a/pkg/compiler/lib/src/resolution/tree_elements.dart
+++ b/pkg/compiler/lib/src/resolution/tree_elements.dart
@@ -100,6 +100,9 @@
/// `true` if the [analyzedElement]'s source code contains a [TryStatement].
bool get containsTryStatement;
+
+ /// Returns native data stored with [node].
+ getNativeData(Node node);
}
class TreeElementMapping extends TreeElements {
@@ -133,6 +136,9 @@
/// Map from labeled goto statements to the labels they target.
Map<GotoStatement, LabelDefinition> _targetLabels;
+ /// Map from nodes to native data.
+ Map<Node, dynamic> _nativeData;
+
final int hashCode = ++_hashCodeCounter;
static int _hashCodeCounter = 0;
@@ -156,8 +162,10 @@
setTreeElement(node, element);
}
+ @override
operator [](Node node) => getTreeElement(node);
+ @override
SendStructure getSendStructure(Send node) {
if (_sendStructureMap == null) return null;
return _sendStructureMap[node];
@@ -170,6 +178,7 @@
_sendStructureMap[node] = sendStructure;
}
+ @override
NewStructure getNewStructure(NewExpression node) {
if (_newStructureMap == null) return null;
return _newStructureMap[node];
@@ -189,8 +198,10 @@
_types[node] = type;
}
+ @override
DartType getType(Node node) => _types != null ? _types[node] : null;
+ @override
Iterable<SourceSpan> get superUses {
return _superUses != null ? _superUses : const <SourceSpan>[];
}
@@ -217,6 +228,7 @@
_setSelector(node, selector);
}
+ @override
Selector getSelector(Node node) => _getSelector(node);
int getSelectorCount() => _selectors == null ? 0 : _selectors.length;
@@ -225,6 +237,7 @@
_setSelector(node.selector, selector);
}
+ @override
Selector getGetterSelectorInComplexSendSet(SendSet node) {
return _getSelector(node.selector);
}
@@ -233,14 +246,17 @@
_setSelector(node.assignmentOperator, selector);
}
+ @override
Selector getOperatorSelectorInComplexSendSet(SendSet node) {
return _getSelector(node.assignmentOperator);
}
+ @override
Element getForInVariable(ForIn node) {
return this[node];
}
+ @override
void setConstant(Node node, ConstantExpression constant) {
if (_constants == null) {
_constants = new Maplet<Node, ConstantExpression>();
@@ -248,18 +264,22 @@
_constants[node] = constant;
}
+ @override
ConstantExpression getConstant(Node node) {
return _constants != null ? _constants[node] : null;
}
+ @override
bool isTypeLiteral(Send node) {
return getType(node) != null;
}
+ @override
DartType getTypeLiteralType(Send node) {
return getType(node);
}
+ @override
List<Node> getPotentialMutations(VariableElement element) {
if (_potentiallyMutated == null) return const <Node>[];
List<Node> mutations = _potentiallyMutated[element];
@@ -274,6 +294,7 @@
_potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode);
}
+ @override
List<Node> getPotentialMutationsIn(Node node, VariableElement element) {
if (_potentiallyMutatedIn == null) return const <Node>[];
Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node];
@@ -295,6 +316,7 @@
mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode);
}
+ @override
List<Node> getPotentialMutationsInClosure(VariableElement element) {
if (_potentiallyMutatedInClosure == null) return const <Node>[];
List<Node> mutations = _potentiallyMutatedInClosure[element];
@@ -312,6 +334,7 @@
.add(mutationNode);
}
+ @override
List<Node> getAccessesByClosureIn(Node node, VariableElement element) {
if (_accessedByClosureIn == null) return const <Node>[];
Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node];
@@ -334,16 +357,19 @@
String toString() => 'TreeElementMapping($analyzedElement)';
+ @override
void forEachConstantNode(f(Node n, ConstantExpression c)) {
if (_constants != null) {
_constants.forEach(f);
}
}
+ @override
FunctionElement getFunctionDefinition(FunctionExpression node) {
return this[node];
}
+ @override
ConstructorElement getRedirectingTargetConstructor(
RedirectingFactoryBody node) {
return this[node];
@@ -365,6 +391,7 @@
}
}
+ @override
JumpTarget getTargetDefinition(Node node) {
return _definedTargets != null ? _definedTargets[node] : null;
}
@@ -376,6 +403,7 @@
_usedTargets[node] = target;
}
+ @override
JumpTarget getTargetOf(GotoStatement node) {
return _usedTargets != null ? _usedTargets[node] : null;
}
@@ -396,6 +424,7 @@
}
}
+ @override
LabelDefinition getLabelDefinition(Label label) {
return _definedLabels != null ? _definedLabels[label] : null;
}
@@ -408,6 +437,7 @@
_targetLabels[node] = label;
}
+ @override
LabelDefinition getTargetLabel(GotoStatement node) {
assert(node.target != null);
return _targetLabels != null ? _targetLabels[node] : null;
@@ -424,24 +454,30 @@
_typeMasks[node] = mask;
}
+ @override
void setTypeMask(Node node, TypeMask mask) {
_setTypeMask(node, mask);
}
+ @override
TypeMask getTypeMask(Node node) => _getTypeMask(node);
+ @override
void setGetterTypeMaskInComplexSendSet(SendSet node, TypeMask mask) {
_setTypeMask(node.selector, mask);
}
+ @override
TypeMask getGetterTypeMaskInComplexSendSet(SendSet node) {
return _getTypeMask(node.selector);
}
+ @override
void setOperatorTypeMaskInComplexSendSet(SendSet node, TypeMask mask) {
_setTypeMask(node.assignmentOperator, mask);
}
+ @override
TypeMask getOperatorTypeMaskInComplexSendSet(SendSet node) {
return _getTypeMask(node.assignmentOperator);
}
@@ -450,27 +486,45 @@
// we're using three selectors, we need to use children of the node,
// and we arbitrarily choose which ones.
+ @override
void setIteratorTypeMask(ForIn node, TypeMask mask) {
_setTypeMask(node, mask);
}
+ @override
TypeMask getIteratorTypeMask(ForIn node) {
return _getTypeMask(node);
}
+ @override
void setMoveNextTypeMask(ForIn node, TypeMask mask) {
_setTypeMask(node.forToken, mask);
}
+ @override
TypeMask getMoveNextTypeMask(ForIn node) {
return _getTypeMask(node.forToken);
}
+ @override
void setCurrentTypeMask(ForIn node, TypeMask mask) {
_setTypeMask(node.inToken, mask);
}
+ @override
TypeMask getCurrentTypeMask(ForIn node) {
return _getTypeMask(node.inToken);
}
+
+ void registerNativeData(Node node, dynamic nativeData) {
+ if (_nativeData == null) {
+ _nativeData = <Node, dynamic>{};
+ }
+ _nativeData[node] = nativeData;
+ }
+
+ @override
+ dynamic getNativeData(Node node) {
+ return _nativeData != null ? _nativeData[node] : null;
+ }
}
diff --git a/pkg/compiler/lib/src/resolved_uri_translator.dart b/pkg/compiler/lib/src/resolved_uri_translator.dart
new file mode 100644
index 0000000..41a96b3
--- /dev/null
+++ b/pkg/compiler/lib/src/resolved_uri_translator.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2016, 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 'common.dart';
+import 'elements/elements.dart' show LibraryElement;
+import 'util/emptyset.dart';
+
+/// API used by the library loader to translate internal SDK URIs into file
+/// system readable URIs.
+abstract class ResolvedUriTranslator {
+ factory ResolvedUriTranslator(
+ Map<String, Uri> sdkLibraries, DiagnosticReporter reporter) =
+ _ResolvedUriTranslator;
+
+ /// The set of platform libraries reported as unsupported.
+ ///
+ /// For instance when importing 'dart:io' without '--categories=Server'.
+ Set<Uri> get disallowedLibraryUris;
+
+ /// Whether or not a mockable library has been translated.
+ bool get mockableLibraryUsed;
+
+ /// A mapping from dart: library names to their location.
+ Map<String, Uri> get sdkLibraries;
+
+ /// Translates the resolved [uri] into a readable URI.
+ ///
+ /// The [importingLibrary] holds the library importing [uri] or `null` if
+ /// [uri] is loaded as the main library. The [importingLibrary] is used to
+ /// grant access to internal libraries from platform libraries and patch
+ /// libraries.
+ ///
+ /// If the [uri] is not accessible from [importingLibrary], this method is
+ /// responsible for reporting errors.
+ ///
+ /// See [LibraryLoader] for terminology on URIs.
+ Uri translate(LibraryElement importingLibrary, Uri uri,
+ [Spannable spannable]);
+}
+
+/// A translator that forwards all methods to an internal
+/// [ResolvedUriTranslator].
+///
+/// The translator to forward to may be set after the instance is constructed.
+/// This is useful for the compiler because some tasks that are instantiated at
+/// compiler construction time need a [ResolvedUriTranslator], but the data
+/// required to instantiate it cannot be obtained at construction time. So a
+/// [ForwardingResolvedUriTranslator] may be passed instead, and the translator
+/// to forward to can be set once the required data has been retrieved.
+class ForwardingResolvedUriTranslator implements ResolvedUriTranslator {
+ ResolvedUriTranslator resolvedUriTranslator;
+
+ /// Returns `true` if [resolvedUriTranslator] is not `null`.
+ bool get isSet => resolvedUriTranslator != null;
+
+ /// The opposite of [isSet].
+ bool get isNotSet => resolvedUriTranslator == null;
+
+ @override
+ Uri translate(LibraryElement importingLibrary, Uri resolvedUri,
+ [Spannable spannable]) =>
+ resolvedUriTranslator.translate(importingLibrary, resolvedUri, spannable);
+
+ @override
+ Set<Uri> get disallowedLibraryUris =>
+ resolvedUriTranslator?.disallowedLibraryUris ??
+ const ImmutableEmptySet<Uri>();
+
+ @override
+ bool get mockableLibraryUsed => resolvedUriTranslator.mockableLibraryUsed;
+
+ @override
+ Map<String, Uri> get sdkLibraries => resolvedUriTranslator.sdkLibraries;
+}
+
+class _ResolvedUriTranslator implements ResolvedUriTranslator {
+ final Map<String, Uri> _sdkLibraries;
+ final DiagnosticReporter _reporter;
+
+ Set<Uri> disallowedLibraryUris = new Set<Uri>();
+ bool mockableLibraryUsed = false;
+
+ _ResolvedUriTranslator(this._sdkLibraries, this._reporter);
+
+ Map<String, Uri> get sdkLibraries => _sdkLibraries;
+
+ @override
+ Uri translate(LibraryElement importingLibrary, Uri uri,
+ [Spannable spannable]) {
+ if (uri.scheme == 'dart') {
+ return translateDartUri(importingLibrary, uri, spannable);
+ }
+ return uri;
+ }
+
+ /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative
+ /// to `options.platformConfigUri` according to the information in the file at
+ /// `options.platformConfigUri`.
+ ///
+ /// Returns `null` and emits an error if the library could not be found or
+ /// imported into [importingLibrary].
+ ///
+ /// Internal libraries (whose name starts with '_') can be only resolved if
+ /// [importingLibrary] is a platform or patch library.
+ Uri translateDartUri(
+ LibraryElement importingLibrary, Uri resolvedUri, Spannable spannable) {
+ Uri location = lookupLibraryUri(resolvedUri.path);
+
+ if (location == null) {
+ _reporter.reportErrorMessage(spannable, MessageKind.LIBRARY_NOT_FOUND,
+ {'resolvedUri': resolvedUri});
+ return null;
+ }
+
+ if (resolvedUri.path.startsWith('_')) {
+ bool allowInternalLibraryAccess = importingLibrary != null &&
+ (importingLibrary.isPlatformLibrary ||
+ importingLibrary.isPatch ||
+ importingLibrary.canonicalUri.path
+ .contains('sdk/tests/compiler/dart2js_native'));
+
+ if (!allowInternalLibraryAccess) {
+ if (importingLibrary != null) {
+ _reporter.reportErrorMessage(
+ spannable, MessageKind.INTERNAL_LIBRARY_FROM, {
+ 'resolvedUri': resolvedUri,
+ 'importingUri': importingLibrary.canonicalUri
+ });
+ } else {
+ _reporter.reportErrorMessage(spannable, MessageKind.INTERNAL_LIBRARY,
+ {'resolvedUri': resolvedUri});
+ registerDisallowedLibraryUse(resolvedUri);
+ }
+ return null;
+ }
+ }
+
+ if (location.scheme == "unsupported") {
+ _reporter.reportErrorMessage(spannable, MessageKind.LIBRARY_NOT_SUPPORTED,
+ {'resolvedUri': resolvedUri});
+ registerDisallowedLibraryUse(resolvedUri);
+ return null;
+ }
+
+ if (resolvedUri.path == 'html' || resolvedUri.path == 'io') {
+ // TODO(ahe): Get rid of mockableLibraryUsed when test.dart
+ // supports this use case better.
+ mockableLibraryUsed = true;
+ }
+ return location;
+ }
+
+ void registerDisallowedLibraryUse(Uri uri) {
+ disallowedLibraryUris.add(uri);
+ }
+
+ Uri lookupLibraryUri(String libraryName) {
+ return _sdkLibraries[libraryName];
+ }
+}
diff --git a/pkg/compiler/lib/src/scanner/array_based_scanner.dart b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
index 27540a4..2496daa 100644
--- a/pkg/compiler/lib/src/scanner/array_based_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
@@ -63,8 +63,8 @@
*/
void appendKeywordToken(Keyword keyword) {
String syntax = keyword.syntax;
- // Type parameters and arguments cannot contain 'this' or 'super'.
- if (identical(syntax, 'this') || identical(syntax, 'super')) {
+ // Type parameters and arguments cannot contain 'this'.
+ if (identical(syntax, 'this')) {
discardOpenLt();
}
tail.next = new KeywordToken(keyword, tokenStart);
diff --git a/pkg/compiler/lib/src/serialization/constant_serialization.dart b/pkg/compiler/lib/src/serialization/constant_serialization.dart
index fae8818..afaa3b4 100644
--- a/pkg/compiler/lib/src/serialization/constant_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/constant_serialization.dart
@@ -232,11 +232,13 @@
decoder.getConstant(Key.NAME),
decoder.getConstant(Key.DEFAULT, isOptional: true));
case ConstantExpressionKind.LIST:
- return new ListConstantExpression(
- decoder.getType(Key.TYPE), decoder.getConstants(Key.VALUES));
+ return new ListConstantExpression(decoder.getType(Key.TYPE),
+ decoder.getConstants(Key.VALUES, isOptional: true));
case ConstantExpressionKind.MAP:
- return new MapConstantExpression(decoder.getType(Key.TYPE),
- decoder.getConstants(Key.KEYS), decoder.getConstants(Key.VALUES));
+ return new MapConstantExpression(
+ decoder.getType(Key.TYPE),
+ decoder.getConstants(Key.KEYS, isOptional: true),
+ decoder.getConstants(Key.VALUES, isOptional: true));
case ConstantExpressionKind.NULL:
return new NullConstantExpression();
case ConstantExpressionKind.STRING:
@@ -249,7 +251,7 @@
return new StringLengthConstantExpression(
decoder.getConstant(Key.EXPRESSION));
case ConstantExpressionKind.SYMBOL:
- break;
+ return new SymbolConstantExpression(decoder.getString(Key.NAME));
case ConstantExpressionKind.TYPE:
return new TypeConstantExpression(decoder.getType(Key.TYPE));
case ConstantExpressionKind.UNARY:
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
index 78228ca..e3d1526 100644
--- a/pkg/compiler/lib/src/serialization/element_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -23,6 +23,7 @@
NAMED_MIXIN_APPLICATION,
GENERATIVE_CONSTRUCTOR,
FACTORY_CONSTRUCTOR,
+ FORWARDING_CONSTRUCTOR,
TOPLEVEL_FIELD,
STATIC_FIELD,
INSTANCE_FIELD,
@@ -105,8 +106,8 @@
if (element.sourcePosition != null) {
SourceSpan position = element.sourcePosition;
encoder.setInt(Key.OFFSET, position.begin);
+ // TODO(johnniwinther): What is the base URI in the case?
if (position.uri != element.compilationUnit.script.resourceUri) {
- // TODO(johnniwinther): What is the base URI in the case?
encoder.setUri(Key.URI, element.library.canonicalUri, position.uri);
}
int length = position.end - position.begin;
@@ -116,6 +117,21 @@
}
}
+ /// Serialize the parent relation for [element] into [encoder], i.e library,
+ /// enclosing class, and compilation unit references.
+ static void serializeParentRelation(Element element, ObjectEncoder encoder) {
+ if (element.enclosingClass != null) {
+ encoder.setElement(Key.CLASS, element.enclosingClass);
+ if (element.enclosingClass.declaration.compilationUnit !=
+ element.compilationUnit) {
+ encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+ }
+ } else {
+ encoder.setElement(Key.LIBRARY, element.library);
+ encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+ }
+ }
+
/// Serialize the parameters of [element] into [encoder].
static void serializeParameters(
FunctionElement element, ObjectEncoder encoder) {
@@ -324,7 +340,11 @@
SerializedElementKind getSerializedKind(Element element) {
if (element.isGenerativeConstructor) {
- return SerializedElementKind.GENERATIVE_CONSTRUCTOR;
+ if (element.enclosingClass.isNamedMixinApplication) {
+ return SerializedElementKind.FORWARDING_CONSTRUCTOR;
+ } else {
+ return SerializedElementKind.GENERATIVE_CONSTRUCTOR;
+ }
} else if (element.isFactoryConstructor) {
return SerializedElementKind.FACTORY_CONSTRUCTOR;
}
@@ -333,19 +353,23 @@
void serialize(ConstructorElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
- encoder.setElement(Key.CLASS, element.enclosingClass);
- encoder.setType(Key.TYPE, element.type);
- encoder.setString(Key.NAME, element.name);
- SerializerUtil.serializePosition(element, encoder);
- SerializerUtil.serializeParameters(element, encoder);
- encoder.setBool(Key.IS_CONST, element.isConst);
- encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
- if (element.isExternal) return;
- if (element.isConst && !element.isFromEnvironmentConstructor) {
- ConstantConstructor constantConstructor = element.constantConstructor;
- ObjectEncoder constantEncoder = encoder.createObject(Key.CONSTRUCTOR);
- const ConstantConstructorSerializer()
- .visit(constantConstructor, constantEncoder);
+ SerializerUtil.serializeParentRelation(element, encoder);
+ if (kind == SerializedElementKind.FORWARDING_CONSTRUCTOR) {
+ encoder.setElement(Key.ELEMENT, element.definingConstructor);
+ } else {
+ encoder.setType(Key.TYPE, element.type);
+ encoder.setString(Key.NAME, element.name);
+ SerializerUtil.serializePosition(element, encoder);
+ SerializerUtil.serializeParameters(element, encoder);
+ encoder.setBool(Key.IS_CONST, element.isConst);
+ encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
+ if (element.isExternal) return;
+ if (element.isConst && !element.isFromEnvironmentConstructor) {
+ ConstantConstructor constantConstructor = element.constantConstructor;
+ ObjectEncoder constantEncoder = encoder.createObject(Key.CONSTRUCTOR);
+ const ConstantConstructorSerializer()
+ .visit(constantConstructor, constantEncoder);
+ }
}
}
}
@@ -378,12 +402,7 @@
ConstantExpression constant = element.constant;
encoder.setConstant(Key.CONSTANT, constant);
}
- if (kind != SerializedElementKind.TOPLEVEL_FIELD) {
- encoder.setElement(Key.CLASS, element.enclosingClass);
- } else {
- encoder.setElement(Key.LIBRARY, element.library);
- encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
- }
+ SerializerUtil.serializeParentRelation(element, encoder);
if (element is EnumConstantElement) {
EnumConstantElement enumConstant = element;
encoder.setInt(Key.INDEX, enumConstant.index);
@@ -430,13 +449,9 @@
encoder.setType(Key.TYPE, element.type);
if (element.isFunction) {
encoder.setBool(Key.IS_OPERATOR, element.isOperator);
+ encoder.setEnum(Key.ASYNC_MARKER, element.asyncMarker);
}
- if (element.enclosingClass != null) {
- encoder.setElement(Key.CLASS, element.enclosingClass);
- } else {
- encoder.setElement(Key.LIBRARY, element.library);
- encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
- }
+ SerializerUtil.serializeParentRelation(element, encoder);
encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
if (element.isLocal) {
LocalFunctionElement localFunction = element;
@@ -508,6 +523,7 @@
encoder.setType(Key.TYPE, element.type);
encoder.setBool(Key.IS_OPTIONAL, element.isOptional);
encoder.setBool(Key.IS_NAMED, element.isNamed);
+ encoder.setBool(Key.IS_FINAL, element.isFinal);
if (element.isOptional) {
encoder.setConstant(Key.CONSTANT, element.constant);
}
@@ -644,6 +660,9 @@
return new GenerativeConstructorElementZ(decoder);
case SerializedElementKind.FACTORY_CONSTRUCTOR:
return new FactoryConstructorElementZ(decoder);
+ case SerializedElementKind.FORWARDING_CONSTRUCTOR:
+ return new ForwardingConstructorElementZ(
+ decoder.getElement(Key.CLASS), decoder.getElement(Key.ELEMENT));
case SerializedElementKind.TOPLEVEL_FUNCTION:
return new TopLevelFunctionElementZ(decoder);
case SerializedElementKind.STATIC_FUNCTION:
@@ -669,7 +688,7 @@
case SerializedElementKind.TYPEVARIABLE:
return new TypeVariableElementZ(decoder);
case SerializedElementKind.PARAMETER:
- return new ParameterElementZ(decoder);
+ return new LocalParameterElementZ(decoder);
case SerializedElementKind.INITIALIZING_FORMAL:
return new InitializingFormalElementZ(decoder);
case SerializedElementKind.IMPORT:
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index d68ce3e..acf3e71 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -11,6 +11,9 @@
import '../dart_types.dart';
import '../elements/elements.dart';
import '../elements/visitor.dart';
+import '../js_backend/backend_serialization.dart'
+ show JavaScriptBackendSerializer;
+import '../native/native.dart' show NativeBehavior;
import '../resolution/access_semantics.dart';
import '../resolution/send_structure.dart';
import '../resolution/tree_elements.dart';
@@ -359,6 +362,8 @@
CompilationUnitElement element1, CompilationUnitElement element2) {
return strategy.test(
element1, element2, 'name', element1.name, element2.name) &&
+ strategy.test(element1, element2, 'script.resourceUri',
+ element1.script.resourceUri, element2.script.resourceUri) &&
visit(element1.library, element2.library);
}
@@ -751,10 +756,20 @@
bool testResolvedAstEquivalence(
ResolvedAst resolvedAst1, ResolvedAst resolvedAst2,
[TestStrategy strategy = const TestStrategy()]) {
+ if (!strategy.test(resolvedAst1, resolvedAst1, 'kind', resolvedAst1.kind,
+ resolvedAst2.kind)) {
+ return false;
+ }
+ if (resolvedAst1.kind != ResolvedAstKind.PARSED) {
+ // Nothing more to check.
+ return true;
+ }
return strategy.testElements(resolvedAst1, resolvedAst2, 'element',
resolvedAst1.element, resolvedAst2.element) &&
new NodeEquivalenceVisitor(strategy).testNodes(resolvedAst1, resolvedAst2,
'node', resolvedAst1.node, resolvedAst2.node) &&
+ new NodeEquivalenceVisitor(strategy).testNodes(resolvedAst1, resolvedAst2,
+ 'body', resolvedAst1.body, resolvedAst2.body) &&
testTreeElementsEquivalence(resolvedAst1, resolvedAst2, strategy);
}
@@ -790,6 +805,83 @@
this.indices1, this.indices2, this.elements1, this.elements2,
[this.strategy = const TestStrategy()]);
+ bool testJumpTargets(
+ Node node1, Node node2, String property, JumpTarget a, JumpTarget b) {
+ if (identical(a, b)) return true;
+ if (a == null || b == null) return false;
+ return strategy.testElements(a, b, 'executableContext', a.executableContext,
+ b.executableContext) &&
+ strategy.test(a, b, 'nestingLevel', a.nestingLevel, b.nestingLevel) &&
+ strategy.test(a, b, 'statement', indices1.nodeIndices[a.statement],
+ indices2.nodeIndices[b.statement]) &&
+ strategy.test(
+ a, b, 'isBreakTarget', a.isBreakTarget, b.isBreakTarget) &&
+ strategy.test(
+ a, b, 'isContinueTarget', a.isContinueTarget, b.isContinueTarget) &&
+ strategy.testLists(a, b, 'labels', a.labels.toList(), b.labels.toList(),
+ (a, b) {
+ return indices1.nodeIndices[a.label] == indices2.nodeIndices[b.label];
+ });
+ }
+
+ bool testLabelDefinitions(Node node1, Node node2, String property,
+ LabelDefinition a, LabelDefinition b) {
+ if (identical(a, b)) return true;
+ if (a == null || b == null) return false;
+ return strategy.test(a, b, 'label', indices1.nodeIndices[a.label],
+ indices2.nodeIndices[b.label]) &&
+ strategy.test(a, b, 'labelName', a.labelName, b.labelName) &&
+ strategy.test(a, b, 'target', indices1.nodeIndices[a.target.statement],
+ indices2.nodeIndices[b.target.statement]) &&
+ strategy.test(
+ a, b, 'isBreakTarget', a.isBreakTarget, b.isBreakTarget) &&
+ strategy.test(
+ a, b, 'isContinueTarget', a.isContinueTarget, b.isContinueTarget);
+ }
+
+ bool testNativeData(Node node1, Node node2, String property, a, b) {
+ if (identical(a, b)) return true;
+ if (a == null || b == null) return false;
+ if (a is NativeBehavior && b is NativeBehavior) {
+ return strategy.test(a, b, 'codeTemplateText', a.codeTemplateText,
+ b.codeTemplateText) &&
+ strategy.test(a, b, 'isAllocation', a.isAllocation, b.isAllocation) &&
+ strategy.test(a, b, 'sideEffects', a.sideEffects, b.sideEffects) &&
+ strategy.test(
+ a, b, 'throwBehavior', a.throwBehavior, b.throwBehavior) &&
+ strategy.testTypeLists(
+ a,
+ b,
+ 'dartTypesReturned',
+ JavaScriptBackendSerializer.filterDartTypes(a.typesReturned),
+ JavaScriptBackendSerializer.filterDartTypes(b.typesReturned)) &&
+ strategy.testLists(
+ a,
+ b,
+ 'specialTypesReturned',
+ JavaScriptBackendSerializer.filterSpecialTypes(a.typesReturned),
+ JavaScriptBackendSerializer
+ .filterSpecialTypes(b.typesReturned)) &&
+ strategy.testTypeLists(
+ a,
+ b,
+ 'dartTypesInstantiated',
+ JavaScriptBackendSerializer.filterDartTypes(a.typesInstantiated),
+ JavaScriptBackendSerializer
+ .filterDartTypes(b.typesInstantiated)) &&
+ strategy.testLists(
+ a,
+ b,
+ 'specialTypesInstantiated',
+ JavaScriptBackendSerializer
+ .filterSpecialTypes(a.typesInstantiated),
+ JavaScriptBackendSerializer
+ .filterSpecialTypes(b.typesInstantiated)) &&
+ strategy.test(a, b, 'useGvn', a.useGvn, b.useGvn);
+ }
+ return true;
+ }
+
visitNode(Node node1) {
if (!success) return;
int index = indices1.nodeIndices[node1];
@@ -808,7 +900,15 @@
strategy.testConstants(node1, node2, 'getConstant($index)',
elements1.getConstant(node1), elements2.getConstant(node2)) &&
strategy.testTypes(node1, node2, 'typesCache[$index]',
- elements1.typesCache[node1], elements2.typesCache[node2]);
+ elements1.typesCache[node1], elements2.typesCache[node2]) &&
+ testJumpTargets(
+ node1,
+ node2,
+ 'getTargetDefinition($index)',
+ elements1.getTargetDefinition(node1),
+ elements2.getTargetDefinition(node2)) &&
+ testNativeData(node1, node2, 'getNativeData($index)',
+ elements1.getNativeData(node1), elements2.getNativeData(node2));
node1.visitChildren(this);
}
@@ -915,6 +1015,36 @@
elements1.getRedirectingTargetConstructor(node1),
elements2.getRedirectingTargetConstructor(node2));
}
+
+ @override
+ visitGotoStatement(GotoStatement node1) {
+ visitStatement(node1);
+ if (!success) return;
+ int index = indices1.nodeIndices[node1];
+ GotoStatement node2 = indices2.nodeList[index];
+ success = testJumpTargets(node1, node2, 'getTargetOf($index)',
+ elements1.getTargetOf(node1), elements2.getTargetOf(node2));
+ if (!success) return;
+ if (node1.target == null && node2.target == null) {
+ return;
+ }
+ success = testLabelDefinitions(node1, node2, 'getTarget($index)',
+ elements1.getTargetLabel(node1), elements2.getTargetLabel(node2));
+ }
+
+ @override
+ visitLabel(Label node1) {
+ visitNode(node1);
+ if (!success) return;
+ int index = indices1.nodeIndices[node1];
+ Label node2 = indices2.nodeList[index];
+ success = testLabelDefinitions(
+ node1,
+ node2,
+ 'getLabelDefinition($index)',
+ elements1.getLabelDefinition(node1),
+ elements2.getLabelDefinition(node2));
+ }
}
class NodeEquivalenceVisitor implements Visitor1<bool, Node> {
@@ -1151,7 +1281,7 @@
node1, node2, 'condition', node1.condition, node2.condition) &&
testNodes(
node1, node2, 'expression', node1.expression, node2.expression) &&
- testNodes(node1, node2, 'body', node1.expression, node2.body) &&
+ testNodes(node1, node2, 'body', node1.body, node2.body) &&
testNodes(node1, node2, 'declaredIdentifier', node1.declaredIdentifier,
node2.declaredIdentifier);
}
diff --git a/pkg/compiler/lib/src/serialization/impact_serialization.dart b/pkg/compiler/lib/src/serialization/impact_serialization.dart
index af3cf5d..7e74259 100644
--- a/pkg/compiler/lib/src/serialization/impact_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/impact_serialization.dart
@@ -4,16 +4,15 @@
library dart2js.serialization.impact;
-import '../dart_types.dart';
+import '../common.dart';
import '../common/resolution.dart';
import '../constants/expressions.dart';
+import '../dart_types.dart';
import '../elements/elements.dart';
-import '../universe/call_structure.dart';
import '../universe/selector.dart';
-import '../universe/world_impact.dart';
import '../universe/use.dart';
+import '../universe/world_impact.dart';
import '../util/enumset.dart';
-
import 'keys.dart';
import 'serialization.dart';
import 'serialization_util.dart';
@@ -21,12 +20,13 @@
/// Visitor that serializes a [ResolutionImpact] object using an
/// [ObjectEncoder].
class ImpactSerializer implements WorldImpactVisitor {
+ final Element element;
final ObjectEncoder objectEncoder;
final ListEncoder staticUses;
final ListEncoder dynamicUses;
final ListEncoder typeUses;
- ImpactSerializer(ObjectEncoder objectEncoder)
+ ImpactSerializer(this.element, ObjectEncoder objectEncoder)
: this.objectEncoder = objectEncoder,
staticUses = objectEncoder.createList(Key.STATIC_USES),
dynamicUses = objectEncoder.createList(Key.DYNAMIC_USES),
@@ -66,14 +66,10 @@
@override
void visitStaticUse(StaticUse staticUse) {
- if (staticUse.element.isGenerativeConstructor &&
- staticUse.element.enclosingClass.isUnnamedMixinApplication) {
- // TODO(johnniwinther): Handle static use of forwarding constructors.
- return;
- }
ObjectEncoder object = staticUses.createObject();
object.setEnum(Key.KIND, staticUse.kind);
- object.setElement(Key.ELEMENT, staticUse.element);
+ serializeElementReference(
+ element, Key.ELEMENT, Key.NAME, object, staticUse.element);
}
@override
@@ -97,29 +93,35 @@
final Iterable<TypeUse> typeUses;
DeserializedResolutionImpact(
- {this.constSymbolNames,
- this.constantLiterals,
- this.dynamicUses,
+ {this.constSymbolNames: const <String>[],
+ this.constantLiterals: const <ConstantExpression>[],
+ this.dynamicUses: const <DynamicUse>[],
EnumSet<Feature> features,
- this.listLiterals,
- this.mapLiterals,
- this.staticUses,
- this.typeUses})
+ this.listLiterals: const <ListLiteralUse>[],
+ this.mapLiterals: const <MapLiteralUse>[],
+ this.staticUses: const <StaticUse>[],
+ this.typeUses: const <TypeUse>[]})
: this._features = features;
- Iterable<Feature> get features => _features.iterable(Feature.values);
+ Iterable<Feature> get features {
+ return _features != null
+ ? _features.iterable(Feature.values)
+ : const <Feature>[];
+ }
}
class ImpactDeserializer {
/// Deserializes a [WorldImpact] from [objectDecoder].
- static ResolutionImpact deserializeImpact(ObjectDecoder objectDecoder) {
+ static ResolutionImpact deserializeImpact(
+ Element element, ObjectDecoder objectDecoder) {
ListDecoder staticUseDecoder = objectDecoder.getList(Key.STATIC_USES);
List<StaticUse> staticUses = <StaticUse>[];
for (int index = 0; index < staticUseDecoder.length; index++) {
ObjectDecoder object = staticUseDecoder.getObject(index);
StaticUseKind kind = object.getEnum(Key.KIND, StaticUseKind.values);
- Element element = object.getElement(Key.ELEMENT);
- staticUses.add(new StaticUse.internal(element, kind));
+ Element usedElement =
+ deserializeElementReference(element, Key.ELEMENT, Key.NAME, object);
+ staticUses.add(new StaticUse.internal(usedElement, kind));
}
ListDecoder dynamicUseDecoder = objectDecoder.getList(Key.DYNAMIC_USES);
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
index d74c820..c7599b2 100644
--- a/pkg/compiler/lib/src/serialization/keys.dart
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -8,6 +8,8 @@
class Key {
static const Key ALIAS = const Key('alias');
static const Key ARGUMENTS = const Key('arguments');
+ static const Key ASYNC_MARKER = const Key('asyncMarker');
+ static const Key BODY = const Key('body');
static const Key BOUND = const Key('bound');
static const Key CACHED_TYPE = const Key('cachedType');
static const Key CALL_STRUCTURE = const Key('callStructure');
@@ -45,7 +47,9 @@
static const Key INTERFACES = const Key('interfaces');
static const Key INDEX = const Key('index');
static const Key IS_ABSTRACT = const Key('isAbstract');
+ static const Key IS_BREAK_TARGET = const Key('isBreakTarget');
static const Key IS_CONST = const Key('isConst');
+ static const Key IS_CONTINUE_TARGET = const Key('isContinueTarget');
static const Key IS_DEFERRED = const Key('isDeferred');
static const Key IS_EMPTY = const Key('isEmpty');
static const Key IS_EXTERNAL = const Key('isExternal');
@@ -57,8 +61,14 @@
static const Key IS_SETTER = const Key('isSetter');
static const Key IS_UNNAMED_MIXIN_APPLICATION =
const Key('isUnnamedMixinApplication');
+ static const Key JUMP_TARGET = const Key('jumpTarget');
+ static const Key JUMP_TARGETS = const Key('jumpTargets');
+ static const Key JUMP_TARGET_DEFINITION = const Key('jumpTargetDefinition');
static const Key KEYS = const Key('keys');
static const Key KIND = const Key('kind');
+ static const Key LABEL_DEFINITION = const Key('labelDefinition');
+ static const Key LABEL_DEFINITIONS = const Key('labelDefinitions');
+ static const Key LABELS = const Key('labels');
static const Key LEFT = const Key('left');
static const Key LENGTH = const Key('length');
static const Key LIBRARY = const Key('library');
@@ -74,7 +84,10 @@
static const Key NAMED_ARGUMENTS = const Key('named-arguments');
static const Key NAMED_PARAMETERS = const Key('named-parameters');
static const Key NAMED_PARAMETER_TYPES = const Key('named-parameter-types');
+ static const Key NATIVE = const Key('native');
+ static const Key NESTING_LEVEL = const Key('nestingLevel');
static const Key NEW_STRUCTURE = const Key('newStructure');
+ static const Key NODE = const Key('node');
static const Key OFFSET = const Key('offset');
static const Key OPERATOR = const Key('operator');
static const Key OPTIONAL_PARAMETER_TYPES =
@@ -94,6 +107,7 @@
static const Key SUPERTYPES = const Key('supertypes');
static const Key SYMBOLS = const Key('symbols');
static const Key TAGS = const Key('tags');
+ static const Key TARGET_LABEL = const Key('targetLabel');
static const Key TRUE = const Key('true');
static const Key TYPE = const Key('type');
static const Key TYPES = const Key('types');
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index e06cb03..5122259 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -13,23 +13,21 @@
import '../common/resolution.dart' show Resolution;
import '../constants/constructors.dart';
import '../constants/expressions.dart';
-import '../core_types.dart';
import '../dart_types.dart';
+import '../elements/common.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart' show FunctionSignatureX;
-import '../elements/common.dart';
import '../elements/visitor.dart';
import '../io/source_file.dart';
import '../ordered_typeset.dart';
import '../resolution/class_members.dart' as class_members;
-import '../resolution/tree_elements.dart' show TreeElements;
import '../resolution/scope.dart' show Scope;
+import '../resolution/tree_elements.dart' show TreeElements;
import '../script.dart';
import '../serialization/constant_serialization.dart';
import '../tokens/token.dart' show Token;
import '../tree/tree.dart';
import '../util/util.dart' show Link, LinkBuilder;
-
import 'keys.dart';
import 'serialization.dart';
@@ -82,13 +80,10 @@
bool get isAbstract => false;
@override
- bool get isAssignable => _unsupported('isAssignable');
-
- @override
bool get isClassMember => false;
@override
- bool get isClosure => _unsupported('isClosure');
+ bool get isClosure => false;
@override
bool get isConst => _unsupported('isConst');
@@ -126,11 +121,6 @@
Iterable<MetadataAnnotation> get metadata => const <MetadataAnnotation>[];
@override
- Element get outermostEnclosingMemberOrTopLevel {
- return _unsupported('outermostEnclosingMemberOrTopLevel');
- }
-
- @override
Token get position => _unsupported('position');
}
@@ -261,8 +251,10 @@
}
abstract class AstElementMixin implements AstElement, ElementZ {
+ // TODO(johnniwinther): This is needed for the token invariant assertion. Find
+ // another way to bypass the test for modelz.
@override
- bool get hasNode => _unsupported('hasNode');
+ bool get hasNode => false;
@override
bool get hasResolvedAst => _unsupported('hasResolvedAst');
@@ -484,6 +476,7 @@
class ScriptZ implements Script {
final Uri resourceUri;
+ SourceFile _file;
ScriptZ(this.resourceUri);
@@ -493,13 +486,27 @@
}
@override
- SourceFile get file => throw new UnsupportedError('ScriptZ.file');
+ SourceFile get file {
+ if (_file == null) {
+ throw new UnsupportedError('ScriptZ.file');
+ }
+ return _file;
+ }
+
+ void set file(SourceFile value) {
+ _file = value;
+ }
@override
bool get isSynthesized => throw new UnsupportedError('ScriptZ.isSynthesized');
@override
- String get name => resourceUri.toString();
+ String get name {
+ if (_file != null) {
+ return _file.filename;
+ }
+ return resourceUri.toString();
+ }
// TODO(johnniwinther): Support the distinction between [readableUri] and
// [resourceUri]; needed for platform libraries.
@@ -507,7 +514,12 @@
Uri get readableUri => resourceUri;
@override
- String get text => throw new UnsupportedError('ScriptZ.text');
+ String get text {
+ if (_file != null) {
+ return _file.slowText();
+ }
+ throw new UnsupportedError('ScriptZ.text');
+ }
}
class CompilationUnitElementZ extends DeserializedElementZ
@@ -588,6 +600,7 @@
abstract class ClassMemberMixin implements DeserializedElementZ {
ClassElement _class;
+ CompilationUnitElement _compilationUnit;
@override
Element get enclosingElement => enclosingClass;
@@ -607,7 +620,16 @@
LibraryElement get library => enclosingClass.library;
@override
- CompilationUnitElement get compilationUnit => enclosingClass.compilationUnit;
+ CompilationUnitElement get compilationUnit {
+ if (_compilationUnit == null) {
+ _compilationUnit =
+ _decoder.getElement(Key.COMPILATION_UNIT, isOptional: true);
+ if (_compilationUnit == null) {
+ _compilationUnit = enclosingClass.compilationUnit;
+ }
+ }
+ return _compilationUnit;
+ }
}
abstract class InstanceMemberMixin implements DeserializedElementZ {
@@ -662,30 +684,34 @@
bool optionalParametersAreNamed = false;
List<DartType> parameterTypes = <DartType>[];
List<DartType> optionalParameterTypes = <DartType>[];
- List<String> namedParameters = <String>[];
- List<DartType> namedParameterTypes = <DartType>[];
for (ParameterElement parameter in parameters) {
if (parameter.isOptional) {
optionalParameterCount++;
- requiredParameters.add(parameter);
+ optionalParameters.add(parameter);
orderedOptionalParameters.add(parameter);
if (parameter.isNamed) {
optionalParametersAreNamed = true;
- namedParameters.add(parameter.name);
- namedParameterTypes.add(parameter.type);
} else {
optionalParameterTypes.add(parameter.type);
}
} else {
requiredParameterCount++;
- optionalParameters.add(parameter);
+ requiredParameters.add(parameter);
parameterTypes.add(parameter.type);
}
}
+ List<String> namedParameters = const <String>[];
+ List<DartType> namedParameterTypes = const <DartType>[];
if (optionalParametersAreNamed) {
+ namedParameters = <String>[];
+ namedParameterTypes = <DartType>[];
orderedOptionalParameters.sort((Element a, Element b) {
return a.name.compareTo(b.name);
});
+ for (ParameterElement parameter in orderedOptionalParameters) {
+ namedParameters.add(parameter.name);
+ namedParameterTypes.add(parameter.type);
+ }
}
FunctionType type = new FunctionType(
@@ -889,33 +915,16 @@
abstract class MixinApplicationElementMixin
implements ElementZ, MixinApplicationElement {
- Link<ConstructorElement> _constructors;
-
@override
- bool get isMixinApplication => false;
+ bool get isMixinApplication => true;
@override
ClassElement get mixin => mixinType.element;
-
- Link<ConstructorElement> get constructors {
- if (_constructors == null) {
- LinkBuilder<ConstructorElement> builder =
- new LinkBuilder<ConstructorElement>();
- for (ConstructorElement definingConstructor in superclass.constructors) {
- if (definingConstructor.isGenerativeConstructor &&
- definingConstructor.memberName.isAccessibleFrom(library)) {
- builder.addLast(
- new ForwardingConstructorElementZ(this, definingConstructor));
- }
- }
- _constructors = builder.toLink();
- }
- return _constructors;
- }
}
class NamedMixinApplicationElementZ extends ClassElementZ
- with MixinApplicationElementCommon, MixinApplicationElementMixin {
+ with MixinApplicationElementMixin {
+ Link<Element> _constructors;
InterfaceType _mixinType;
NamedMixinApplicationElementZ(ObjectDecoder decoder) : super(decoder);
@@ -939,6 +948,7 @@
final InterfaceType supertype;
final Link<DartType> interfaces;
OrderedTypeSet _allSupertypesAndSelf;
+ Link<ConstructorElement> _constructors;
UnnamedMixinApplicationElementZ(
ClassElement subclass, InterfaceType supertype, InterfaceType mixin)
@@ -953,6 +963,22 @@
@override
bool get isUnnamedMixinApplication => true;
+ Link<ConstructorElement> get constructors {
+ if (_constructors == null) {
+ LinkBuilder<ConstructorElement> builder =
+ new LinkBuilder<ConstructorElement>();
+ for (ConstructorElement definingConstructor in superclass.constructors) {
+ if (definingConstructor.isGenerativeConstructor &&
+ definingConstructor.memberName.isAccessibleFrom(library)) {
+ builder.addLast(
+ new ForwardingConstructorElementZ(this, definingConstructor));
+ }
+ }
+ _constructors = builder.toLink();
+ }
+ return _constructors;
+ }
+
@override
List<DartType> _getTypeVariables() {
// Create synthetic type variables for the mixin application.
@@ -1072,7 +1098,7 @@
}
@override
- AsyncMarker get asyncMarker => _unsupported('asyncMarker');
+ AsyncMarker get asyncMarker => AsyncMarker.SYNC;
@override
InterfaceType computeEffectiveTargetType(InterfaceType newType) {
@@ -1336,6 +1362,11 @@
}
@override
+ AsyncMarker get asyncMarker {
+ return _decoder.getEnum(Key.ASYNC_MARKER, AsyncMarker.values);
+ }
+
+ @override
bool get isOperator => _decoder.getBool(Key.IS_OPERATOR);
}
@@ -1430,6 +1461,9 @@
accept(ElementVisitor visitor, arg) {
return visitor.visitGetterElement(this, arg);
}
+
+ @override
+ AsyncMarker get asyncMarker => AsyncMarker.SYNC;
}
class TopLevelGetterElementZ extends GetterElementZ with LibraryMemberMixin {
@@ -1467,6 +1501,9 @@
accept(ElementVisitor visitor, arg) {
return visitor.visitSetterElement(this, arg);
}
+
+ @override
+ AsyncMarker get asyncMarker => AsyncMarker.SYNC;
}
class TopLevelSetterElementZ extends SetterElementZ with LibraryMemberMixin {
@@ -1698,7 +1735,7 @@
SourceSpan get sourcePosition => typeDeclaration.sourcePosition;
}
-class ParameterElementZ extends DeserializedElementZ
+abstract class ParameterElementZ extends DeserializedElementZ
with AnalyzableElementMixin, AstElementMixin, TypedElementMixin
implements ParameterElement {
FunctionElement _functionDeclaration;
@@ -1708,9 +1745,10 @@
ParameterElementZ(ObjectDecoder decoder) : super(decoder);
@override
- accept(ElementVisitor visitor, arg) {
- return visitor.visitParameterElement(this, arg);
- }
+ bool get isFinal => _decoder.getBool(Key.IS_FINAL);
+
+ @override
+ bool get isConst => false;
@override
ConstantExpression get constant {
@@ -1755,15 +1793,25 @@
bool get isOptional => _decoder.getBool(Key.IS_OPTIONAL);
@override
- ElementKind get kind => ElementKind.PARAMETER;
-
- @override
LibraryElement get library => executableContext.library;
@override
MemberElement get memberContext => executableContext.memberContext;
}
+class LocalParameterElementZ extends ParameterElementZ
+ implements LocalParameterElement {
+ LocalParameterElementZ(ObjectDecoder decoder) : super(decoder);
+
+ @override
+ accept(ElementVisitor visitor, arg) {
+ return visitor.visitParameterElement(this, arg);
+ }
+
+ @override
+ ElementKind get kind => ElementKind.PARAMETER;
+}
+
class InitializingFormalElementZ extends ParameterElementZ
implements InitializingFormalElement {
FieldElement _fieldElement;
@@ -1808,9 +1856,12 @@
ElementKind get kind => ElementKind.VARIABLE;
@override
+ bool get isFinal => _decoder.getBool(Key.IS_FINAL);
+
+ @override
bool get isConst {
if (_isConst == null) {
- _constant = _decoder.getConstant(Key.CONSTANT);
+ _constant = _decoder.getConstant(Key.CONSTANT, isOptional: true);
_isConst = _constant != null;
}
return _isConst;
diff --git a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
index d25426e..eb03860 100644
--- a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
@@ -10,15 +10,17 @@
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../elements/elements.dart';
-import '../parser/parser.dart' show Parser;
+import '../elements/modelx.dart';
import '../parser/listener.dart' show ParserError;
import '../parser/node_listener.dart' show NodeListener;
+import '../parser/parser.dart' show Parser;
import '../resolution/enum_creator.dart';
import '../resolution/send_structure.dart';
import '../resolution/tree_elements.dart';
-import '../tree/tree.dart';
import '../tokens/token.dart';
+import '../tree/tree.dart';
import '../universe/selector.dart';
+import '../util/util.dart';
import 'keys.dart';
import 'serialization.dart';
import 'serialization_util.dart';
@@ -54,13 +56,15 @@
/// Serializer for [ResolvedAst]s.
class ResolvedAstSerializer extends Visitor {
+ final SerializerPlugin nativeDataSerializer;
final ObjectEncoder objectEncoder;
final ResolvedAst resolvedAst;
final AstIndexComputer indexComputer = new AstIndexComputer();
final Map<int, ObjectEncoder> nodeData = <int, ObjectEncoder>{};
ListEncoder _nodeDataEncoder;
- ResolvedAstSerializer(this.objectEncoder, this.resolvedAst);
+ ResolvedAstSerializer(
+ this.objectEncoder, this.resolvedAst, this.nativeDataSerializer);
AstElement get element => resolvedAst.element;
@@ -71,12 +75,44 @@
Map<Node, int> get nodeIndices => indexComputer.nodeIndices;
List<Node> get nodeList => indexComputer.nodeList;
+ Map<JumpTarget, int> jumpTargetMap = <JumpTarget, int>{};
+ Map<LabelDefinition, int> labelDefinitionMap = <LabelDefinition, int>{};
+
+ /// Returns the unique id for [jumpTarget], creating it if necessary.
+ int getJumpTargetId(JumpTarget jumpTarget) {
+ return jumpTargetMap.putIfAbsent(jumpTarget, () => jumpTargetMap.length);
+ }
+
+ /// Returns the unique id for [labelDefinition], creating it if necessary.
+ int getLabelDefinitionId(LabelDefinition labelDefinition) {
+ return labelDefinitionMap.putIfAbsent(
+ labelDefinition, () => labelDefinitionMap.length);
+ }
+
/// Serializes [resolvedAst] into [objectEncoder].
void serialize() {
+ objectEncoder.setEnum(Key.KIND, resolvedAst.kind);
+ switch (resolvedAst.kind) {
+ case ResolvedAstKind.PARSED:
+ serializeParsed();
+ break;
+ case ResolvedAstKind.DEFAULT_CONSTRUCTOR:
+ case ResolvedAstKind.FORWARDING_CONSTRUCTOR:
+ // No additional properties.
+ break;
+ }
+ }
+
+ /// Serialize [ResolvedAst] that is defined in terms of an AST together with
+ /// [TreeElements].
+ void serializeParsed() {
objectEncoder.setUri(
Key.URI,
elements.analyzedElement.compilationUnit.script.resourceUri,
elements.analyzedElement.compilationUnit.script.resourceUri);
+ if (resolvedAst.body != null) {
+ objectEncoder.setInt(Key.BODY, nodeIndices[resolvedAst.body]);
+ }
AstKind kind;
if (element.enclosingClass is EnumClassElement) {
if (element.name == 'index') {
@@ -110,9 +146,47 @@
}
}
}
- objectEncoder.setEnum(Key.KIND, kind);
+ objectEncoder.setEnum(Key.SUB_KIND, kind);
root.accept(indexComputer);
root.accept(this);
+ if (jumpTargetMap.isNotEmpty) {
+ ListEncoder list = objectEncoder.createList(Key.JUMP_TARGETS);
+ for (JumpTarget jumpTarget in jumpTargetMap.keys) {
+ serializeJumpTarget(jumpTarget, list.createObject());
+ }
+ }
+ if (labelDefinitionMap.isNotEmpty) {
+ ListEncoder list = objectEncoder.createList(Key.LABEL_DEFINITIONS);
+ for (LabelDefinition labelDefinition in labelDefinitionMap.keys) {
+ serializeLabelDefinition(labelDefinition, list.createObject());
+ }
+ }
+ }
+
+ /// Serialize [target] into [encoder].
+ void serializeJumpTarget(JumpTarget jumpTarget, ObjectEncoder encoder) {
+ encoder.setElement(Key.EXECUTABLE_CONTEXT, jumpTarget.executableContext);
+ encoder.setInt(Key.NODE, nodeIndices[jumpTarget.statement]);
+ encoder.setInt(Key.NESTING_LEVEL, jumpTarget.nestingLevel);
+ encoder.setBool(Key.IS_BREAK_TARGET, jumpTarget.isBreakTarget);
+ encoder.setBool(Key.IS_CONTINUE_TARGET, jumpTarget.isContinueTarget);
+ if (jumpTarget.labels.isNotEmpty) {
+ List<int> labelIdList = <int>[];
+ for (LabelDefinition label in jumpTarget.labels) {
+ labelIdList.add(getLabelDefinitionId(label));
+ }
+ encoder.setInts(Key.LABELS, labelIdList);
+ }
+ }
+
+ /// Serialize [label] into [encoder].
+ void serializeLabelDefinition(
+ LabelDefinition labelDefinition, ObjectEncoder encoder) {
+ encoder.setInt(Key.NODE, nodeIndices[labelDefinition.label]);
+ encoder.setString(Key.NAME, labelDefinition.labelName);
+ encoder.setBool(Key.IS_BREAK_TARGET, labelDefinition.isBreakTarget);
+ encoder.setBool(Key.IS_CONTINUE_TARGET, labelDefinition.isContinueTarget);
+ encoder.setInt(Key.JUMP_TARGET, getJumpTargetId(labelDefinition.target));
}
/// Computes the [ListEncoder] for serializing data for nodes.
@@ -137,13 +211,8 @@
visitNode(Node node) {
Element nodeElement = elements[node];
if (nodeElement != null) {
- if (nodeElement.enclosingClass != null &&
- nodeElement.enclosingClass.isUnnamedMixinApplication) {
- // TODO(johnniwinther): Handle references to members of unnamed mixin
- // applications.
- } else {
- getNodeDataEncoder(node).setElement(Key.ELEMENT, nodeElement);
- }
+ serializeElementReference(element, Key.ELEMENT, Key.NAME,
+ getNodeDataEncoder(node), nodeElement);
}
DartType type = elements.getType(node);
if (type != null) {
@@ -162,7 +231,16 @@
if (cachedType != null) {
getNodeDataEncoder(node).setType(Key.CACHED_TYPE, cachedType);
}
- // TODO(johnniwinther): Serialize [JumpTarget]s.
+ JumpTarget jumpTargetDefinition = elements.getTargetDefinition(node);
+ if (jumpTargetDefinition != null) {
+ getNodeDataEncoder(node).setInt(
+ Key.JUMP_TARGET_DEFINITION, getJumpTargetId(jumpTargetDefinition));
+ }
+ var nativeData = elements.getNativeData(node);
+ if (nativeData != null) {
+ nativeDataSerializer.onData(
+ nativeData, getNodeDataEncoder(node).createObject(Key.NATIVE));
+ }
node.visitChildren(this);
}
@@ -189,13 +267,28 @@
@override
visitGotoStatement(GotoStatement node) {
visitStatement(node);
- // TODO(johnniwinther): Serialize [JumpTarget]s and [LabelDefinition]s.
+ JumpTarget jumpTarget = elements.getTargetOf(node);
+ if (jumpTarget != null) {
+ getNodeDataEncoder(node)
+ .setInt(Key.JUMP_TARGET, getJumpTargetId(jumpTarget));
+ }
+ if (node.target != null) {
+ LabelDefinition targetLabel = elements.getTargetLabel(node);
+ if (targetLabel != null) {
+ getNodeDataEncoder(node)
+ .setInt(Key.TARGET_LABEL, getLabelDefinitionId(targetLabel));
+ }
+ }
}
@override
visitLabel(Label node) {
visitNode(node);
- // TODO(johnniwinther): Serialize[LabelDefinition]s.
+ LabelDefinition labelDefinition = elements.getLabelDefinition(node);
+ if (labelDefinition != null) {
+ getNodeDataEncoder(node)
+ .setInt(Key.LABEL_DEFINITION, getLabelDefinitionId(labelDefinition));
+ }
}
}
@@ -214,8 +307,32 @@
/// Deserializes the [ResolvedAst] for [element] from [objectDecoder].
/// [parsing] and [getBeginToken] are used for parsing the [Node] for
/// [element] from its source code.
- static ResolvedAst deserialize(Element element, ObjectDecoder objectDecoder,
- Parsing parsing, Token getBeginToken(Uri uri, int charOffset)) {
+ static ResolvedAst deserialize(
+ Element element,
+ ObjectDecoder objectDecoder,
+ ParsingContext parsing,
+ Token getBeginToken(Uri uri, int charOffset),
+ DeserializerPlugin nativeDataDeserializer) {
+ ResolvedAstKind kind =
+ objectDecoder.getEnum(Key.KIND, ResolvedAstKind.values);
+ switch (kind) {
+ case ResolvedAstKind.PARSED:
+ return deserializeParsed(element, objectDecoder, parsing, getBeginToken,
+ nativeDataDeserializer);
+ case ResolvedAstKind.DEFAULT_CONSTRUCTOR:
+ case ResolvedAstKind.FORWARDING_CONSTRUCTOR:
+ return new SynthesizedResolvedAst(element, kind);
+ }
+ }
+
+ /// Deserialize a [ResolvedAst] that is defined in terms of an AST together
+ /// with [TreeElements].
+ static ResolvedAst deserializeParsed(
+ Element element,
+ ObjectDecoder objectDecoder,
+ ParsingContext parsing,
+ Token getBeginToken(Uri uri, int charOffset),
+ DeserializerPlugin nativeDataDeserializer) {
CompilationUnitElement compilationUnit = element.compilationUnit;
DiagnosticReporter reporter = parsing.reporter;
@@ -366,21 +483,77 @@
}
}
- AstKind kind = objectDecoder.getEnum(Key.KIND, AstKind.values);
+ AstKind kind = objectDecoder.getEnum(Key.SUB_KIND, AstKind.values);
Node root = computeNode(kind);
TreeElementMapping elements = new TreeElementMapping(element);
AstIndexComputer indexComputer = new AstIndexComputer();
Map<Node, int> nodeIndices = indexComputer.nodeIndices;
List<Node> nodeList = indexComputer.nodeList;
+ Node body;
+ int bodyNodeIndex = objectDecoder.getInt(Key.BODY, isOptional: true);
+ if (bodyNodeIndex != null) {
+ body = nodeList[bodyNodeIndex];
+ }
root.accept(indexComputer);
+
+ List<JumpTarget> jumpTargets = <JumpTarget>[];
+ Map<JumpTarget, List<int>> jumpTargetLabels = <JumpTarget, List<int>>{};
+ List<LabelDefinition> labelDefinitions = <LabelDefinition>[];
+
+ ListDecoder jumpTargetsDecoder =
+ objectDecoder.getList(Key.JUMP_TARGETS, isOptional: true);
+ if (jumpTargetsDecoder != null) {
+ for (int i = 0; i < jumpTargetsDecoder.length; i++) {
+ ObjectDecoder decoder = jumpTargetsDecoder.getObject(i);
+ ExecutableElement executableContext =
+ decoder.getElement(Key.EXECUTABLE_CONTEXT);
+ Node statement = nodeList[decoder.getInt(Key.NODE)];
+ int nestingLevel = decoder.getInt(Key.NESTING_LEVEL);
+ JumpTarget jumpTarget =
+ new JumpTargetX(statement, nestingLevel, executableContext);
+ jumpTarget.isBreakTarget = decoder.getBool(Key.IS_BREAK_TARGET);
+ jumpTarget.isContinueTarget = decoder.getBool(Key.IS_CONTINUE_TARGET);
+ jumpTargetLabels[jumpTarget] =
+ decoder.getInts(Key.LABELS, isOptional: true);
+ jumpTargets.add(jumpTarget);
+ }
+ }
+
+ ListDecoder labelDefinitionsDecoder =
+ objectDecoder.getList(Key.LABEL_DEFINITIONS, isOptional: true);
+ if (labelDefinitionsDecoder != null) {
+ for (int i = 0; i < labelDefinitionsDecoder.length; i++) {
+ ObjectDecoder decoder = labelDefinitionsDecoder.getObject(i);
+ Label label = nodeList[decoder.getInt(Key.NODE)];
+ String labelName = decoder.getString(Key.NAME);
+ JumpTarget target = jumpTargets[decoder.getInt(Key.JUMP_TARGET)];
+ LabelDefinitionX labelDefinition =
+ new LabelDefinitionX(label, labelName, target);
+ labelDefinition.isBreakTarget = decoder.getBool(Key.IS_BREAK_TARGET);
+ labelDefinition.isContinueTarget =
+ decoder.getBool(Key.IS_CONTINUE_TARGET);
+ labelDefinitions.add(labelDefinition);
+ }
+ }
+ jumpTargetLabels.forEach((JumpTargetX jumpTarget, List<int> labelIds) {
+ if (labelIds.isEmpty) return;
+ LinkBuilder<LabelDefinition> linkBuilder =
+ new LinkBuilder<LabelDefinition>();
+ for (int labelId in labelIds) {
+ linkBuilder.addLast(labelDefinitions[labelId]);
+ }
+ jumpTarget.labels = linkBuilder.toLink();
+ });
+
ListDecoder dataDecoder = objectDecoder.getList(Key.DATA);
if (dataDecoder != null) {
for (int i = 0; i < dataDecoder.length; i++) {
ObjectDecoder objectDecoder = dataDecoder.getObject(i);
int id = objectDecoder.getInt(Key.ID);
Node node = nodeList[id];
- Element nodeElement =
- objectDecoder.getElement(Key.ELEMENT, isOptional: true);
+ Element nodeElement = deserializeElementReference(
+ element, Key.ELEMENT, Key.NAME, objectDecoder,
+ isOptional: true);
if (nodeElement != null) {
elements[node] = nodeElement;
}
@@ -415,8 +588,36 @@
elements.setNewStructure(
node, deserializeNewStructure(newStructureDecoder));
}
+ int targetDefinitionId =
+ objectDecoder.getInt(Key.JUMP_TARGET_DEFINITION, isOptional: true);
+ if (targetDefinitionId != null) {
+ elements.defineTarget(node, jumpTargets[targetDefinitionId]);
+ }
+ int targetOfId =
+ objectDecoder.getInt(Key.JUMP_TARGET, isOptional: true);
+ if (targetOfId != null) {
+ elements.registerTargetOf(node, jumpTargets[targetOfId]);
+ }
+ int labelDefinitionId =
+ objectDecoder.getInt(Key.LABEL_DEFINITION, isOptional: true);
+ if (labelDefinitionId != null) {
+ elements.defineLabel(node, labelDefinitions[labelDefinitionId]);
+ }
+ int targetLabelId =
+ objectDecoder.getInt(Key.TARGET_LABEL, isOptional: true);
+ if (targetLabelId != null) {
+ elements.registerTargetLabel(node, labelDefinitions[targetLabelId]);
+ }
+ ObjectDecoder nativeDataDecoder =
+ objectDecoder.getObject(Key.NATIVE, isOptional: true);
+ if (nativeDataDecoder != null) {
+ var nativeData = nativeDataDeserializer.onData(nativeDataDecoder);
+ if (nativeData != null) {
+ elements.registerNativeData(node, nativeData);
+ }
+ }
}
}
- return new ResolvedAst(element, root, elements);
+ return new ParsedResolvedAst(element, root, body, elements);
}
}
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 1521f39..a16e558 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -682,6 +682,7 @@
if (element == null) {
throw new ArgumentError('Serializer._getElementDataObject(null)');
}
+ element = element.declaration;
DataObject dataObject = _elementMap[element];
if (dataObject == null) {
if (!shouldInclude(element)) {
@@ -856,6 +857,9 @@
/// Use [creatorEncoder] to create a data object with id [tag] for storing
/// additional data for [element].
void onElement(Element element, ObjectEncoder createEncoder(String tag)) {}
+
+ /// Called to serialize custom [data].
+ void onData(var data, ObjectEncoder encoder) {}
}
/// Plugin for deserializing additional data for an [Element].
@@ -867,6 +871,9 @@
/// Use [getDecoder] to retrieve the data object with id [tag] stored for
/// [element]. If not object is stored for [tag], [getDecoder] returns `null`.
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {}
+
+ /// Called to deserialize custom data from [decoder].
+ dynamic onData(ObjectDecoder decoder) {}
}
/// Context for parallel deserialization.
diff --git a/pkg/compiler/lib/src/serialization/serialization_util.dart b/pkg/compiler/lib/src/serialization/serialization_util.dart
index cd5e77a..24aa6f8 100644
--- a/pkg/compiler/lib/src/serialization/serialization_util.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_util.dart
@@ -4,19 +4,15 @@
library dart2js.serialization.util;
-import '../dart_types.dart';
-import '../common/resolution.dart';
+import '../common.dart';
import '../constants/expressions.dart';
+import '../dart_types.dart';
import '../elements/elements.dart';
import '../resolution/access_semantics.dart';
import '../resolution/operators.dart';
import '../resolution/send_structure.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
-import '../universe/world_impact.dart';
-import '../universe/use.dart';
-import '../util/enumset.dart';
-
import 'keys.dart';
import 'serialization.dart';
@@ -479,3 +475,45 @@
throw new UnsupportedError('Unsupported access kind: $kind');
}
}
+
+/// Serialize a reference from [context] to an [element] which might be a member
+/// of an unnamed mixin application. If it is, [element] is by serialized
+/// indirectly by name in the [nameKey] of [encoder], otherwise [element] is
+/// serialized directly in [elementKey] in [encoder].
+void serializeElementReference(Element context, Key elementKey, Key nameKey,
+ ObjectEncoder encoder, Element element) {
+ if (element.isGenerativeConstructor &&
+ element.enclosingClass.isUnnamedMixinApplication) {
+ assert(invariant(element, element.isConstructor,
+ message: "Unexpected reference of forwarding constructor "
+ "${element} from $context."));
+ encoder.setString(nameKey, element.name);
+ } else {
+ encoder.setElement(elementKey, element);
+ }
+}
+
+/// Deserialize a reference from [context] to an [Element] which might be a
+/// member of an unnamed mixin application. If it is, the [Element] is by
+/// deserialized indirectly by name from [nameKey] in [decoder], otherwise
+/// the [Element] is deserialized directly from [elementKey] in [encoder].
+Element deserializeElementReference(
+ Element context, Key elementKey, Key nameKey, ObjectDecoder decoder,
+ {bool isOptional: false}) {
+ Element element = decoder.getElement(elementKey, isOptional: true);
+ if (element == null) {
+ String elementName = decoder.getString(nameKey, isOptional: isOptional);
+ if (elementName == null) {
+ return null;
+ }
+ assert(invariant(NO_LOCATION_SPANNABLE, context.isConstructor,
+ message: "Unexpected reference of forwarding constructor "
+ "'${elementName}' from $context."));
+ ClassElement superclass = context.enclosingClass.superclass;
+ element = superclass.lookupConstructor(elementName);
+ assert(invariant(NO_LOCATION_SPANNABLE, element != null,
+ message: "Unresolved reference of forwarding constructor "
+ "'${elementName}' from $context."));
+ }
+ return element;
+}
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 1289b77..0eb9db0 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -46,6 +46,16 @@
return deserializer != null && deserializer.isDeserialized(element);
}
+ bool hasResolutionImpact(Element element) {
+ return deserializer != null && deserializer.hasResolutionImpact(element);
+ }
+
+ ResolutionImpact getResolutionImpact(Element element) {
+ return deserializer != null
+ ? deserializer.getResolutionImpact(element)
+ : null;
+ }
+
/// Creates the [ResolutionWorkItem] for the deserialized [element].
ResolutionWorkItem createResolutionWorkItem(
Element element, ItemCompilationContext context) {
@@ -54,6 +64,14 @@
return new DeserializedResolutionWorkItem(
element, context, deserializer.computeWorldImpact(element));
}
+
+ bool hasResolvedAst(Element element) {
+ return deserializer != null ? deserializer.hasResolvedAst(element) : false;
+ }
+
+ ResolvedAst getResolvedAst(Element element) {
+ return deserializer != null ? deserializer.getResolvedAst(element) : null;
+ }
}
/// A [ResolutionWorkItem] for a deserialized element.
@@ -84,7 +102,9 @@
abstract class DeserializerSystem {
Future<LibraryElement> readLibrary(Uri resolvedUri);
bool isDeserialized(Element element);
+ bool hasResolvedAst(Element element);
ResolvedAst getResolvedAst(Element element);
+ bool hasResolutionImpact(Element element);
ResolutionImpact getResolutionImpact(Element element);
WorldImpact computeWorldImpact(Element element);
}
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index e5b3a03..da15419 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -8,16 +8,16 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
-
-import '../compiler.dart' as api show Diagnostic, DiagnosticHandler;
-import '../compiler_new.dart' as api show CompilerInput, CompilerDiagnostics;
-import 'dart2js.dart' show AbortLeg;
-import 'colors.dart' as colors;
-import 'io/source_file.dart';
-import 'filenames.dart';
-import 'util/uri_extras.dart';
import 'dart:typed_data';
+
+import '../compiler.dart' as api show Diagnostic;
+import '../compiler_new.dart' as api;
import '../compiler_new.dart';
+import 'colors.dart' as colors;
+import 'dart2js.dart' show AbortLeg;
+import 'filenames.dart';
+import 'io/source_file.dart';
+import 'util/uri_extras.dart';
List<int> readAll(String filename) {
var file = (new File(filename)).openSync();
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index a05158d..acfdef0 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -18,9 +18,9 @@
import '../core_types.dart' show CoreClasses;
import '../dart_types.dart';
import '../diagnostics/messages.dart' show Message, MessageTemplate;
+import '../dump_info.dart' show InfoReporter;
import '../elements/elements.dart';
-import '../elements/modelx.dart'
- show ConstructorBodyElementX, ElementX, VariableElementX;
+import '../elements/modelx.dart' show ConstructorBodyElementX;
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/backend_helpers.dart' show BackendHelpers;
@@ -37,11 +37,9 @@
import '../universe/side_effects.dart' show SideEffects;
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
import '../util/util.dart';
-import '../world.dart' show ClassWorld, World;
-import '../dump_info.dart' show InfoReporter;
-
-import 'nodes.dart';
+import '../world.dart' show ClassWorld;
import 'codegen.dart';
+import 'nodes.dart';
import 'optimize.dart';
import 'types.dart';
@@ -109,7 +107,7 @@
return reporter.withCurrentElement(element, () {
SsaBuilder builder = new SsaBuilder(
work.element.implementation,
- work.resolutionTree,
+ work.resolvedAst,
work.compilationContext,
work.registry,
backend,
@@ -326,11 +324,11 @@
*
* Invariant: [function] must be an implementation element.
*/
- void startFunction(Element element, ast.Node node) {
+ void startFunction(AstElement element, ast.Node node) {
assert(invariant(element, element.isImplementation));
Compiler compiler = builder.compiler;
- closureData = compiler.closureToClassMapper
- .computeClosureToClassMapping(element, node, builder.elements);
+ closureData = compiler.closureToClassMapper.computeClosureToClassMapping(
+ compiler.backend.frontend.getResolvedAst(element.declaration));
if (element is FunctionElement) {
FunctionElement functionElement = element;
@@ -459,7 +457,8 @@
builder.reporter.internalError(builder.compiler.currentElement,
"Runtime type information not available for $local.");
} else {
- builder.reporter.internalError(local, "Cannot find value $local.");
+ builder.reporter.internalError(
+ local, "Cannot find value $local in ${directLocals.keys}.");
}
}
HInstruction value = directLocals[local];
@@ -1005,8 +1004,7 @@
/// The element for which this SSA builder is being used.
final Element target;
- /// Reference to resolved elements in [target]'s AST.
- TreeElements elements;
+ ResolvedAst resolvedAst;
/// Used to report information about inlining (which occurs while building the
/// SSA graph), when dump-info is enabled.
@@ -1120,7 +1118,7 @@
// TODO(sigmund): make most args optional
SsaBuilder(
this.target,
- this.elements,
+ this.resolvedAst,
this.context,
this.registry,
JavaScriptBackend backend,
@@ -1149,6 +1147,9 @@
CoreClasses get coreClasses => compiler.coreClasses;
+ /// Reference to resolved elements in [target]'s AST.
+ TreeElements get elements => resolvedAst.elements;
+
@override
SemanticSendVisitor get sendVisitor => this;
@@ -1377,6 +1378,7 @@
if (compiler.elementHasCompileTimeError(element)) return false;
FunctionElement function = element;
+ ResolvedAst functionResolvedAst = backend.frontend.getResolvedAst(function);
bool insideLoop = loopNesting > 0 || graph.calledInLoop;
// Bail out early if the inlining decision is in the cache and we can't
@@ -1436,7 +1438,7 @@
bool doesNotContainCode() {
// A function with size 1 does not contain any code.
- return InlineWeeder.canBeInlined(function, 1, true,
+ return InlineWeeder.canBeInlined(functionResolvedAst, 1, true,
enableUserAssertions: compiler.options.enableUserAssertions);
}
@@ -1444,7 +1446,7 @@
// The call is on a path which is executed rarely, so inline only if it
// does not make the program larger.
if (isCalledOnce(element)) {
- return InlineWeeder.canBeInlined(function, -1, false,
+ return InlineWeeder.canBeInlined(functionResolvedAst, -1, false,
enableUserAssertions: compiler.options.enableUserAssertions);
}
// TODO(sra): Measure if inlining would 'reduce' the size. One desirable
@@ -1482,7 +1484,7 @@
if (cachedCanBeInlined == true) {
// We may have forced the inlining of some methods. Therefore check
// if we can inline this method regardless of size.
- assert(InlineWeeder.canBeInlined(function, -1, false,
+ assert(InlineWeeder.canBeInlined(functionResolvedAst, -1, false,
allowLoops: true,
enableUserAssertions: compiler.options.enableUserAssertions));
return true;
@@ -1507,7 +1509,7 @@
}
bool canInline;
canInline = InlineWeeder.canBeInlined(
- function, maxInliningNodes, useMaxInliningNodes,
+ functionResolvedAst, maxInliningNodes, useMaxInliningNodes,
enableUserAssertions: compiler.options.enableUserAssertions);
if (canInline) {
backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop);
@@ -1531,7 +1533,7 @@
}
List<HInstruction> compiledArguments = completeSendArgumentsList(
function, selector, providedArguments, currentNode);
- enterInlinedMethod(function, currentNode, compiledArguments,
+ enterInlinedMethod(function, functionResolvedAst, compiledArguments,
instanceType: instanceType);
inlinedFrom(function, () {
if (!isReachable) {
@@ -1678,7 +1680,7 @@
HGraph buildMethod(FunctionElement functionElement) {
assert(invariant(functionElement, functionElement.isImplementation));
graph.calledInLoop = compiler.world.isCalledInLoop(functionElement);
- ast.FunctionExpression function = functionElement.node;
+ ast.FunctionExpression function = resolvedAst.node;
assert(function != null);
assert(elements.getFunctionDefinition(function) != null);
openFunction(functionElement, function);
@@ -1832,9 +1834,12 @@
void setupStateForInlining(
FunctionElement function, List<HInstruction> compiledArguments,
{InterfaceType instanceType}) {
+ ResolvedAst resolvedAst =
+ compiler.backend.frontend.getResolvedAst(function.declaration);
+ assert(resolvedAst != null);
localsHandler = new LocalsHandler(this, function, instanceType);
- localsHandler.closureData = compiler.closureToClassMapper
- .computeClosureToClassMapping(function, function.node, elements);
+ localsHandler.closureData =
+ compiler.closureToClassMapper.computeClosureToClassMapping(resolvedAst);
returnLocal = new SyntheticLocal("result", function);
localsHandler.updateLocal(returnLocal, graph.addConstantNull(compiler));
@@ -1863,8 +1868,6 @@
}
assert(argumentIndex == compiledArguments.length);
- elements = function.resolvedAst.elements;
- assert(elements != null);
returnType = signature.type.returnType;
stack = <HInstruction>[];
@@ -1876,7 +1879,7 @@
localsHandler = state.oldLocalsHandler;
returnLocal = state.oldReturnLocal;
inTryStatement = state.inTryStatement;
- elements = state.oldElements;
+ resolvedAst = state.oldResolvedAst;
returnType = state.oldReturnType;
assert(stack.isEmpty);
stack = state.oldStack;
@@ -2007,21 +2010,69 @@
});
// Build the initializers in the context of the new constructor.
- TreeElements oldElements = elements;
- ResolvedAst resolvedAst = callee.resolvedAst;
- elements = resolvedAst.elements;
+ ResolvedAst oldResolvedAst = resolvedAst;
+ resolvedAst = backend.frontend.getResolvedAst(callee);
ClosureClassMap oldClosureData = localsHandler.closureData;
- ast.Node node = resolvedAst.node;
ClosureClassMap newClosureData = compiler.closureToClassMapper
- .computeClosureToClassMapping(callee, node, elements);
+ .computeClosureToClassMapping(resolvedAst);
localsHandler.closureData = newClosureData;
- localsHandler.enterScope(node, callee);
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ localsHandler.enterScope(resolvedAst.node, callee);
+ }
buildInitializers(callee, constructors, fieldValues);
localsHandler.closureData = oldClosureData;
- elements = oldElements;
+ resolvedAst = oldResolvedAst;
});
}
+ void buildInitializers(
+ ConstructorElement constructor,
+ List<FunctionElement> constructors,
+ Map<Element, HInstruction> fieldValues) {
+ assert(invariant(
+ constructor, resolvedAst.element == constructor.declaration,
+ message: "Expected ResolvedAst for $constructor, found $resolvedAst"));
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ buildParsedInitializers(constructor, constructors, fieldValues);
+ } else {
+ buildSynthesizedConstructorInitializers(
+ constructor, constructors, fieldValues);
+ }
+ }
+
+ void buildSynthesizedConstructorInitializers(
+ ConstructorElement constructor,
+ List<FunctionElement> constructors,
+ Map<Element, HInstruction> fieldValues) {
+ assert(invariant(constructor, constructor.isSynthesized));
+ List<HInstruction> arguments = <HInstruction>[];
+ HInstruction compileArgument(ParameterElement parameter) {
+ return localsHandler.readLocal(parameter);
+ }
+
+ Element target = constructor.definingConstructor.implementation;
+ bool match = !target.isMalformed &&
+ CallStructure.addForwardingElementArgumentsToList(
+ constructor,
+ arguments,
+ target,
+ compileArgument,
+ handleConstantForOptionalParameter);
+ if (!match) {
+ if (compiler.elementHasCompileTimeError(constructor)) {
+ return;
+ }
+ // If this fails, the selector we constructed for the call to a
+ // forwarding constructor in a mixin application did not match the
+ // constructor (which, for example, may happen when the libraries are
+ // not compatible for private names, see issue 20394).
+ reporter.internalError(
+ constructor, 'forwarding constructor call does not match');
+ }
+ inlineSuperOrRedirect(
+ target, arguments, constructors, fieldValues, constructor);
+ }
+
/**
* Run through the initializers and inline all field initializers. Recursively
* inlines super initializers.
@@ -2032,40 +2083,13 @@
* Invariant: The [constructor] and elements in [constructors] must all be
* implementation elements.
*/
- void buildInitializers(
+ void buildParsedInitializers(
ConstructorElement constructor,
List<FunctionElement> constructors,
Map<Element, HInstruction> fieldValues) {
assert(invariant(constructor, constructor.isImplementation));
- if (constructor.isSynthesized) {
- List<HInstruction> arguments = <HInstruction>[];
- HInstruction compileArgument(ParameterElement parameter) {
- return localsHandler.readLocal(parameter);
- }
-
- Element target = constructor.definingConstructor.implementation;
- bool match = !target.isMalformed &&
- CallStructure.addForwardingElementArgumentsToList(
- constructor,
- arguments,
- target,
- compileArgument,
- handleConstantForOptionalParameter);
- if (!match) {
- if (compiler.elementHasCompileTimeError(constructor)) {
- return;
- }
- // If this fails, the selector we constructed for the call to a
- // forwarding constructor in a mixin application did not match the
- // constructor (which, for example, may happen when the libraries are
- // not compatible for private names, see issue 20394).
- reporter.internalError(
- constructor, 'forwarding constructor call does not match');
- }
- inlineSuperOrRedirect(
- target, arguments, constructors, fieldValues, constructor);
- return;
- }
+ assert(invariant(constructor, !constructor.isSynthesized,
+ message: "Unexpected synthesized constructor: $constructor"));
ast.FunctionExpression functionNode = constructor.node;
bool foundSuperOrRedirect = false;
@@ -2143,7 +2167,6 @@
(ClassElement enclosingClass, VariableElement member) {
if (compiler.elementHasCompileTimeError(member)) return;
reporter.withCurrentElement(member, () {
- TreeElements definitions = member.treeElements;
ast.Node node = member.node;
ast.Expression initializer = member.initializer;
if (initializer == null) {
@@ -2154,14 +2177,14 @@
}
} else {
ast.Node right = initializer;
- TreeElements savedElements = elements;
- elements = definitions;
+ ResolvedAst savedResolvedAst = resolvedAst;
+ resolvedAst = backend.frontend.getResolvedAst(member);
// In case the field initializer uses closures, run the
// closure to class mapper.
compiler.closureToClassMapper
- .computeClosureToClassMapping(member, node, elements);
+ .computeClosureToClassMapping(resolvedAst);
inlinedFrom(member, () => right.accept(this));
- elements = savedElements;
+ resolvedAst = savedResolvedAst;
fieldValues[member] = pop();
}
});
@@ -2362,7 +2385,7 @@
bodyCallInputs.add(interceptor);
}
bodyCallInputs.add(newObject);
- ResolvedAst resolvedAst = constructor.resolvedAst;
+ ResolvedAst resolvedAst = backend.frontend.getResolvedAst(constructor);
ast.Node node = resolvedAst.node;
ClosureClassMap parameterClosureData =
compiler.closureToClassMapper.getMappingForNestedFunction(node);
@@ -3436,8 +3459,6 @@
/// Generate read access of an unresolved static or top level entity.
void generateStaticUnresolvedGet(ast.Send node, Element element) {
if (element is ErroneousElement) {
- SourceInformation sourceInformation =
- sourceInformationBuilder.buildGet(node);
// An erroneous element indicates an unresolved static getter.
handleInvalidStaticGet(node, element);
} else {
@@ -4015,8 +4036,9 @@
reporter.internalError(
node.argumentsNode, 'At least two arguments expected.');
}
- native.NativeBehavior nativeBehavior =
- compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ native.NativeBehavior nativeBehavior = elements.getNativeData(node);
+ assert(invariant(node, nativeBehavior != null,
+ message: "No NativeBehavior for $node"));
List<HInstruction> inputs = <HInstruction>[];
addGenericSendArgumentsToList(link.tail.tail, inputs);
@@ -4183,8 +4205,9 @@
compiledArguments.add(pop());
}
- native.NativeBehavior nativeBehavior =
- compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ native.NativeBehavior nativeBehavior = elements.getNativeData(node);
+ assert(invariant(node, nativeBehavior != null,
+ message: "No NativeBehavior for $node"));
TypeMask ssaType =
TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler);
@@ -4228,8 +4251,9 @@
String globalName = constant.primitiveValue.slowToString();
js.Template expr = js.js.expressionTemplateYielding(
backend.emitter.generateEmbeddedGlobalAccess(globalName));
- native.NativeBehavior nativeBehavior =
- compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ native.NativeBehavior nativeBehavior = elements.getNativeData(node);
+ assert(invariant(node, nativeBehavior != null,
+ message: "No NativeBehavior for $node"));
TypeMask ssaType =
TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler);
push(new HForeignCode(expr, ssaType, const [],
@@ -4866,10 +4890,10 @@
constructorDeclaration == helpers.jsArrayTypedConstructor;
if (isSymbolConstructor) {
- constructor = compiler.symbolValidatedConstructor;
+ constructor = helpers.symbolValidatedConstructor;
assert(invariant(send, constructor != null,
message: 'Constructor Symbol.validated is missing'));
- callStructure = compiler.symbolValidatedConstructorSelector.callStructure;
+ callStructure = helpers.symbolValidatedConstructorSelector.callStructure;
assert(invariant(send, callStructure != null,
message: 'Constructor Symbol.validated is missing'));
}
@@ -5524,17 +5548,10 @@
}
}
- bool _hasNamedParameters(FunctionElement function) {
- FunctionSignature params = function.functionSignature;
- return params.optionalParameterCount > 0 &&
- params.optionalParametersAreNamed;
- }
-
HForeignCode invokeJsInteropFunction(FunctionElement element,
List<HInstruction> arguments, SourceInformation sourceInformation) {
assert(backend.isJsInterop(element));
nativeEmitter.nativeMethods.add(element);
- String templateString;
if (element.isFactoryConstructor &&
backend.jsInteropAnalysis
@@ -6583,7 +6600,7 @@
int position = 0;
- for (ParameterElement targetParameter in targetRequireds) {
+ for (ParameterElement _ in targetRequireds) {
loadPosition(position++, null);
}
@@ -6905,7 +6922,6 @@
// method is inlined. We would require full scalar replacement in that
// case.
- Selector selector = Selectors.iterator;
TypeMask mask = elements.getIteratorTypeMask(node);
ClassWorld classWorld = compiler.world;
@@ -7869,18 +7885,19 @@
* This method is invoked before inlining the body of [function] into this
* [SsaBuilder].
*/
- void enterInlinedMethod(FunctionElement function, ast.Node _,
- List<HInstruction> compiledArguments,
+ void enterInlinedMethod(FunctionElement function,
+ ResolvedAst functionResolvedAst, List<HInstruction> compiledArguments,
{InterfaceType instanceType}) {
AstInliningState state = new AstInliningState(
function,
returnLocal,
returnType,
- elements,
+ resolvedAst,
stack,
localsHandler,
inTryStatement,
allInlinedFunctionsCalledOnce && isFunctionCalledOnce(function));
+ resolvedAst = functionResolvedAst;
inliningStack.add(state);
// Setting up the state of the (AST) builder is performed even when the
@@ -8077,14 +8094,14 @@
this.enableUserAssertions);
static bool canBeInlined(
- FunctionElement function, int maxInliningNodes, bool useMaxInliningNodes,
+ ResolvedAst resolvedAst, int maxInliningNodes, bool useMaxInliningNodes,
{bool allowLoops: false, bool enableUserAssertions: null}) {
assert(enableUserAssertions is bool); // Ensure we passed it.
- if (function.resolvedAst.elements.containsTryStatement) return false;
+ if (resolvedAst.elements.containsTryStatement) return false;
InlineWeeder weeder = new InlineWeeder(maxInliningNodes,
useMaxInliningNodes, allowLoops, enableUserAssertions);
- ast.FunctionExpression functionExpression = function.node;
+ ast.FunctionExpression functionExpression = resolvedAst.node;
weeder.visit(functionExpression.initializers);
weeder.visit(functionExpression.body);
weeder.visit(functionExpression.asyncModifier);
@@ -8196,7 +8213,7 @@
class AstInliningState extends InliningState {
final Local oldReturnLocal;
final DartType oldReturnType;
- final TreeElements oldElements;
+ final ResolvedAst oldResolvedAst;
final List<HInstruction> oldStack;
final LocalsHandler oldLocalsHandler;
final bool inTryStatement;
@@ -8206,7 +8223,7 @@
FunctionElement function,
this.oldReturnLocal,
this.oldReturnType,
- this.oldElements,
+ this.oldResolvedAst,
this.oldStack,
this.oldLocalsHandler,
this.inTryStatement,
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 3a5d85a..5938e1c 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -15,17 +15,16 @@
import '../js/js.dart' as js;
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart';
-import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
+import '../js_emitter/js_emitter.dart' show NativeEmitter;
import '../native/native.dart' as native;
import '../types/types.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
import '../util/util.dart';
-import '../world.dart' show ClassWorld, World;
-
-import 'nodes.dart';
+import '../world.dart' show ClassWorld;
import 'codegen_helpers.dart';
+import 'nodes.dart';
import 'variable_allocator.dart';
class SsaCodeGeneratorTask extends CompilerTask {
@@ -40,7 +39,8 @@
NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
js.Fun buildJavaScriptFunction(
- FunctionElement element, List<js.Parameter> parameters, js.Block body) {
+ ResolvedAst resolvedAst, List<js.Parameter> parameters, js.Block body) {
+ FunctionElement element = resolvedAst.element;
js.AsyncModifier asyncModifier = element.asyncMarker.isAsync
? (element.asyncMarker.isYielding
? const js.AsyncModifier.asyncStar()
@@ -51,8 +51,8 @@
return new js.Fun(parameters, body, asyncModifier: asyncModifier)
.withSourceInformation(sourceInformationFactory
- .createBuilderForContext(element)
- .buildDeclaration(element));
+ .createBuilderForContext(resolvedAst.element)
+ .buildDeclaration(resolvedAst));
}
js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
@@ -63,12 +63,12 @@
}
}
- js.Expression generateLazyInitializer(work, graph) {
+ js.Expression generateLazyInitializer(CodegenWorkItem work, HGraph graph) {
return measure(() {
compiler.tracer.traceGraph("codegen", graph);
SourceInformation sourceInformation = sourceInformationFactory
.createBuilderForContext(work.element)
- .buildDeclaration(work.element);
+ .buildDeclaration(work.resolvedAst);
SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work);
codegen.visitGraph(graph);
return new js.Fun(codegen.parameters, codegen.body)
@@ -85,7 +85,8 @@
SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work);
codegen.visitGraph(graph);
compiler.tracer.traceGraph("codegen", graph);
- return buildJavaScriptFunction(element, codegen.parameters, codegen.body);
+ return buildJavaScriptFunction(
+ work.resolvedAst, codegen.parameters, codegen.body);
});
}
}
@@ -1613,7 +1614,6 @@
var isolate = new js.VariableUse(
backend.namer.globalObjectFor(helpers.interceptorsLibrary));
Selector selector = node.selector;
- TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
js.Name methodName = backend.registerOneShotInterceptor(selector);
push(js
.propertyCall(isolate, methodName, arguments)
@@ -2182,15 +2182,12 @@
{SourceInformation sourceInformation}) {
js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper);
List arguments = [];
- var location;
if (argument is List) {
- location = argument[0];
argument.forEach((instruction) {
use(instruction);
arguments.add(pop());
});
} else {
- location = argument;
use(argument);
arguments.add(pop());
}
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 1777d96..3249c31 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.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 '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
+import '../common/codegen.dart' show CodegenWorkItem;
import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
import '../constants/values.dart';
@@ -11,8 +11,7 @@
import '../js_backend/js_backend.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
-import '../world.dart' show ClassWorld, World;
-
+import '../world.dart' show ClassWorld;
import 'nodes.dart';
import 'optimize.dart';
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index ff565f9..cf05b2e 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
@@ -8,10 +8,9 @@
import '../elements/elements.dart';
import '../js_backend/js_backend.dart';
import '../types/types.dart';
-import '../universe/selector.dart';
import '../universe/call_structure.dart';
-import '../world.dart' show ClassWorld, World;
-
+import '../universe/selector.dart';
+import '../world.dart' show World;
import 'nodes.dart';
import 'types.dart';
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index a779457..4b55e48 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -20,10 +20,9 @@
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
import '../util/util.dart';
-import '../world.dart' show ClassWorld, World;
-
-import 'validate.dart';
+import '../world.dart' show ClassWorld;
import 'invoke_dynamic_specializers.dart';
+import 'validate.dart';
abstract class HVisitor<R> {
R visitAdd(HAdd node);
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 4f67597..7d01871 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.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 '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
+import '../common/codegen.dart' show CodegenWorkItem;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
@@ -20,13 +20,12 @@
import '../universe/side_effects.dart' show SideEffects;
import '../util/util.dart';
import '../world.dart' show ClassWorld, World;
-
+import 'interceptor_simplifier.dart';
import 'nodes.dart';
-import 'types_propagation.dart';
import 'types.dart';
+import 'types_propagation.dart';
import 'value_range_analyzer.dart';
import 'value_set.dart';
-import 'interceptor_simplifier.dart';
abstract class OptimizationPhase {
String get name;
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 2a7ecff..7efebe7 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -10,7 +10,7 @@
import '../tree/tree.dart' as ast;
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
-import '../world.dart' show ClassWorld, World;
+import '../world.dart' show ClassWorld;
class TypeMaskFactory {
static TypeMask fromInferredType(TypeMask mask, Compiler compiler) {
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index e5ad513..64e4c30 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -7,8 +7,7 @@
import '../js_backend/js_backend.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
-import '../world.dart' show ClassWorld, World;
-
+import '../world.dart' show ClassWorld;
import 'nodes.dart';
import 'optimize.dart';
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index 8893e90..c811c71 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -2,13 +2,12 @@
// 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 '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
+import '../common/codegen.dart' show CodegenWorkItem;
import '../compiler.dart' show Compiler;
import '../constant_system_dart.dart';
import '../constants/constant_system.dart';
import '../constants/values.dart';
import '../js_backend/js_backend.dart';
-
import 'nodes.dart';
import 'optimize.dart';
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index 9335fef..ae8111b 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -5,15 +5,14 @@
import 'dart:collection' show IterableMixin;
import '../common.dart';
-import '../tokens/precedence_constants.dart' as Precedence show FUNCTION_INFO;
-import '../tokens/token.dart' show BeginGroupToken, Token;
-import '../tokens/token_constants.dart' as Tokens
- show IDENTIFIER_TOKEN, KEYWORD_TOKEN, PLUS_TOKEN;
-import '../util/util.dart';
-import '../util/characters.dart';
+import '../elements/elements.dart' show MetadataAnnotation;
import '../resolution/secret_tree_element.dart'
show NullTreeElementMixin, StoredTreeElementMixin;
-import '../elements/elements.dart' show MetadataAnnotation;
+import '../tokens/precedence_constants.dart' as Precedence show FUNCTION_INFO;
+import '../tokens/token.dart' show BeginGroupToken, Token;
+import '../tokens/token_constants.dart' as Tokens show PLUS_TOKEN;
+import '../util/characters.dart';
+import '../util/util.dart';
import 'dartstring.dart';
import 'prettyprint.dart';
import 'unparser.dart';
@@ -1737,8 +1736,9 @@
class TypeVariable extends Node {
final Identifier name;
+ final Token extendsOrSuper;
final TypeAnnotation bound;
- TypeVariable(Identifier this.name, TypeAnnotation this.bound);
+ TypeVariable(this.name, this.extendsOrSuper, this.bound);
accept(Visitor visitor) => visitor.visitTypeVariable(this);
diff --git a/pkg/compiler/lib/src/tree/prettyprint.dart b/pkg/compiler/lib/src/tree/prettyprint.dart
index dceffaf..837db37 100644
--- a/pkg/compiler/lib/src/tree/prettyprint.dart
+++ b/pkg/compiler/lib/src/tree/prettyprint.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 '../tokens/token.dart' show BeginGroupToken, Token;
+import '../tokens/token.dart' show Token;
import '../util/util.dart';
import 'nodes.dart';
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index bb1d38e..37838eb 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.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 '../tokens/token.dart' show BeginGroupToken, Token;
+import '../tokens/token.dart' show Token;
import '../tokens/token_constants.dart' as Tokens
show IDENTIFIER_TOKEN, KEYWORD_TOKEN, PLUS_TOKEN;
import '../util/util.dart';
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 39b4bb1..effd18d 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -587,7 +587,6 @@
return 'Await($value)';
}
- @override
String visitYield(Yield node) {
String value = visitExpression(node.input);
return 'Yield($value)';
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index 9593b10..e186ee4 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -4,10 +4,10 @@
library dart2js.typechecker;
-import 'common.dart';
import 'common/names.dart' show Identifiers;
import 'common/resolution.dart' show Resolution;
import 'common/tasks.dart' show CompilerTask;
+import 'common.dart';
import 'compiler.dart' show Compiler;
import 'constants/expressions.dart';
import 'constants/values.dart';
@@ -30,7 +30,6 @@
GetterElement,
InitializingFormalElement,
LibraryElement,
- Member,
MemberSignature,
Name,
ParameterElement,
@@ -40,10 +39,9 @@
SetterElement,
TypeDeclarationElement,
TypedElement,
- TypedefElement,
VariableElement;
-import 'resolution/tree_elements.dart' show TreeElements;
import 'resolution/class_members.dart' show MembersCreator;
+import 'resolution/tree_elements.dart' show TreeElements;
import 'tree/tree.dart';
import 'util/util.dart' show Link, LinkBuilder;
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index fb9c908..84c0a62 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -5,11 +5,10 @@
library dart2js.call_structure;
import '../common.dart';
-import '../common/names.dart' show Identifiers, Names, Selectors;
+import '../common/names.dart' show Names;
import '../elements/elements.dart';
import '../tree/tree.dart';
import '../util/util.dart';
-
import 'selector.dart' show Selector;
/// The structure of the arguments at a call-site.
diff --git a/pkg/compiler/lib/src/universe/side_effects.dart b/pkg/compiler/lib/src/universe/side_effects.dart
index 2c39999..280d56a 100644
--- a/pkg/compiler/lib/src/universe/side_effects.dart
+++ b/pkg/compiler/lib/src/universe/side_effects.dart
@@ -33,6 +33,8 @@
clearAllSideEffects();
}
+ SideEffects.fromFlags(this._flags);
+
bool operator ==(other) => _flags == other._flags;
int get hashCode => throw new UnsupportedError('SideEffects.hashCode');
@@ -147,6 +149,8 @@
_flags = other._flags;
}
+ int get flags => _flags;
+
String toString() {
StringBuffer buffer = new StringBuffer();
buffer.write('Depends on');
diff --git a/pkg/compiler/lib/src/universe/world_impact.dart b/pkg/compiler/lib/src/universe/world_impact.dart
index 45dcba5..1ba0ab7 100644
--- a/pkg/compiler/lib/src/universe/world_impact.dart
+++ b/pkg/compiler/lib/src/universe/world_impact.dart
@@ -4,10 +4,8 @@
library dart2js.universe.world_impact;
-import '../elements/elements.dart'
- show Element, LocalFunctionElement, MethodElement;
+import '../elements/elements.dart' show Element;
import '../util/util.dart' show Setlet;
-
import 'use.dart' show DynamicUse, StaticUse, TypeUse;
class WorldImpact {
diff --git a/pkg/compiler/samples/darttags/darttags.dart b/pkg/compiler/samples/darttags/darttags.dart
index 0333c69..d77966d 100644
--- a/pkg/compiler/samples/darttags/darttags.dart
+++ b/pkg/compiler/samples/darttags/darttags.dart
@@ -29,20 +29,16 @@
// Where DART_LOCATION is the gclient directory where you found .gclient.
import 'dart:io';
-
import 'dart:mirrors';
-import 'package:sdk_library_metadata/libraries.dart'
- show libraries, LibraryInfo;
-
-import 'package:compiler/src/mirrors/analyze.dart' show analyze;
-import 'package:compiler/src/mirrors/dart2js_mirrors.dart' show BackDoor;
-import 'package:compiler/src/mirrors/mirrors_util.dart' show nameOf;
-
import 'package:compiler/src/filenames.dart';
import 'package:compiler/src/io/source_file.dart';
+import 'package:compiler/src/mirrors/analyze.dart' show analyze;
+import 'package:compiler/src/mirrors/dart2js_mirrors.dart' show BackDoor;
+import 'package:compiler/src/mirrors/mirrors_util.dart' show nameOf;
import 'package:compiler/src/source_file_provider.dart';
import 'package:compiler/src/util/uri_extras.dart';
+import 'package:sdk_library_metadata/libraries.dart' show libraries;
const DART2JS = 'package:compiler/src/dart2js.dart';
const DART2JS_MIRROR = 'package:compiler/src/mirrors/dart2js_mirrors.dart';
diff --git a/pkg/compiler/samples/jsonify/jsonify.dart b/pkg/compiler/samples/jsonify/jsonify.dart
index db8020d..a84cb04 100644
--- a/pkg/compiler/samples/jsonify/jsonify.dart
+++ b/pkg/compiler/samples/jsonify/jsonify.dart
@@ -3,18 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:io';
import 'dart:convert';
-
+import 'dart:io';
import 'dart:mirrors';
-import 'package:sdk_library_metadata/libraries.dart'
- show libraries, LibraryInfo;
-
-import '../../lib/src/mirrors/analyze.dart' show analyze;
-import '../../lib/src/mirrors/dart2js_mirrors.dart' show BackDoor;
+import 'package:sdk_library_metadata/libraries.dart' show libraries;
import '../../lib/src/filenames.dart';
+import '../../lib/src/mirrors/analyze.dart' show analyze;
+import '../../lib/src/mirrors/dart2js_mirrors.dart' show BackDoor;
import '../../lib/src/source_file_provider.dart';
import '../../lib/src/util/uri_extras.dart';
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index a5cdc02..7994891 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -683,7 +683,7 @@
PartialFunctionElement before,
PartialFunctionElement after) {
FunctionExpression node =
- after.parseNode(compiler.parsing).asFunctionExpression();
+ after.parseNode(compiler.parsingContext).asFunctionExpression();
if (node == null) {
return cannotReuse(after, "Not a function expression: '$node'");
}
@@ -705,7 +705,7 @@
Token diffToken,
PartialClassElement before,
PartialClassElement after) {
- ClassNode node = after.parseNode(compiler.parsing).asClassNode();
+ ClassNode node = after.parseNode(compiler.parsingContext).asClassNode();
if (node == null) {
return cannotReuse(after, "Not a ClassNode: '$node'");
}
diff --git a/pkg/fixnum/LICENSE b/pkg/fixnum/LICENSE
deleted file mode 100644
index 5c60afe..0000000
--- a/pkg/fixnum/LICENSE
+++ /dev/null
@@ -1,26 +0,0 @@
-Copyright 2014, the Dart project authors. All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of Google Inc. nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/fixnum/README.md b/pkg/fixnum/README.md
deleted file mode 100644
index 81f6467..0000000
--- a/pkg/fixnum/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-fixnum
-======
-
-A fixed-size integer library for Dart.
-- - -
-The fixnum package provides data types for signed 32- and 64-bit integers.
-The integer implementations in this library are designed to work identically
-whether executed on the Dart VM or compiled to JavaScript.
-
-Installing
-----------
-
-Use [pub](http://pub.dartlang.org) to install this package. Add the following
-to your `pubspec.yaml` file:
-
- dependencies:
- fixnum: any
-
-Then run `pub install`.
-
-For more information, see the
-[fixnum package on pub.dartlang.org](http://pub.dartlang.org/packages/fixnum).
diff --git a/pkg/fixnum/lib/fixnum.dart b/pkg/fixnum/lib/fixnum.dart
deleted file mode 100644
index fe21c47..0000000
--- a/pkg/fixnum/lib/fixnum.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Signed 32- and 64-bit integer support.
- *
- * The integer implementations in this library are designed to work
- * identically whether executed on the Dart VM or compiled to JavaScript.
- *
- * For information on installing and importing this library, see the
- * [fixnum package on pub.dartlang.org]
- * (http://pub.dartlang.org/packages/fixnum).
- */
-library fixnum;
-
-part 'src/intx.dart';
-part 'src/int32.dart';
-part 'src/int64.dart';
diff --git a/pkg/fixnum/lib/src/int32.dart b/pkg/fixnum/lib/src/int32.dart
deleted file mode 100644
index 8e0dcca..0000000
--- a/pkg/fixnum/lib/src/int32.dart
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of fixnum;
-
-/**
- * An immutable 32-bit signed integer, in the range [-2^31, 2^31 - 1].
- * Arithmetic operations may overflow in order to maintain this range.
- */
-class Int32 implements IntX {
-
- /**
- * The maximum positive value attainable by an [Int32], namely
- * 2147483647.
- */
- static const Int32 MAX_VALUE = const Int32._internal(0x7FFFFFFF);
-
- /**
- * The minimum positive value attainable by an [Int32], namely
- * -2147483648.
- */
- static const Int32 MIN_VALUE = const Int32._internal(-0x80000000);
-
- /**
- * An [Int32] constant equal to 0.
- */
- static const Int32 ZERO = const Int32._internal(0);
-
- /**
- * An [Int32] constant equal to 1.
- */
- static const Int32 ONE = const Int32._internal(1);
-
- /**
- * An [Int32] constant equal to 2.
- */
- static const Int32 TWO = const Int32._internal(2);
-
- // Hex digit char codes
- static const int _CC_0 = 48; // '0'.codeUnitAt(0)
- static const int _CC_9 = 57; // '9'.codeUnitAt(0)
- static const int _CC_a = 97; // 'a'.codeUnitAt(0)
- static const int _CC_z = 122; // 'z'.codeUnitAt(0)
- static const int _CC_A = 65; // 'A'.codeUnitAt(0)
- static const int _CC_Z = 90; // 'Z'.codeUnitAt(0)
-
- static int _decodeDigit(int c) {
- if (c >= _CC_0 && c <= _CC_9) {
- return c - _CC_0;
- } else if (c >= _CC_a && c <= _CC_z) {
- return c - _CC_a + 10;
- } else if (c >= _CC_A && c <= _CC_Z) {
- return c - _CC_A + 10;
- } else {
- return -1; // bad char code
- }
- }
-
- static int _validateRadix(int radix) {
- if (2 <= radix && radix <= 36) return radix;
- throw new RangeError.range(radix, 2, 36, 'radix');
- }
-
- /**
- * Parses a [String] in a given [radix] between 2 and 16 and returns an
- * [Int32].
- */
- // TODO(rice) - Make this faster by converting several digits at once.
- static Int32 parseRadix(String s, int radix) {
- _validateRadix(radix);
- Int32 x = ZERO;
- for (int i = 0; i < s.length; i++) {
- int c = s.codeUnitAt(i);
- int digit = _decodeDigit(c);
- if (digit < 0 || digit >= radix) {
- throw new FormatException("Non-radix code unit: $c");
- }
- x = (x * radix) + digit;
- }
- return x;
- }
-
- /**
- * Parses a decimal [String] and returns an [Int32].
- */
- static Int32 parseInt(String s) => new Int32(int.parse(s));
-
- /**
- * Parses a hexadecimal [String] and returns an [Int32].
- */
- static Int32 parseHex(String s) => parseRadix(s, 16);
-
- // Assumes i is <= 32-bit.
- static int _bitCount(int i) {
- // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
-
- // The basic strategy is to use "divide and conquer" to
- // add pairs (then quads, etc.) of bits together to obtain
- // sub-counts.
- //
- // A straightforward approach would look like:
- //
- // i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
- // i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
- // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
- // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
- // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
- //
- // The code below removes unnecessary &'s and uses a
- // trick to remove one instruction in the first line.
-
- i -= ((i >> 1) & 0x55555555);
- i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
- i = ((i + (i >> 4)) & 0x0F0F0F0F);
- i += (i >> 8);
- i += (i >> 16);
- return (i & 0x0000003F);
- }
-
- // Assumes i is <= 32-bit
- static int _numberOfLeadingZeros(int i) {
- i |= i >> 1;
- i |= i >> 2;
- i |= i >> 4;
- i |= i >> 8;
- i |= i >> 16;
- return _bitCount(~i);
- }
-
- static int _numberOfTrailingZeros(int i) => _bitCount((i & -i) - 1);
-
- // The internal value, kept in the range [MIN_VALUE, MAX_VALUE].
- final int _i;
-
- const Int32._internal(int i) : _i = i;
-
- /**
- * Constructs an [Int32] from an [int]. Only the low 32 bits of the input
- * are used.
- */
- Int32([int i=0]) : _i = (i & 0x7fffffff) - (i & 0x80000000);
-
- // Returns the [int] representation of the specified value. Throws
- // [ArgumentError] for non-integer arguments.
- int _toInt(val) {
- if (val is Int32) {
- return val._i;
- } else if (val is int) {
- return val;
- }
- throw new ArgumentError(val);
- }
-
- // The +, -, * , &, |, and ^ operaters deal with types as follows:
- //
- // Int32 + int => Int32
- // Int32 + Int32 => Int32
- // Int32 + Int64 => Int64
- //
- // The %, ~/ and remainder operators return an Int32 even with an Int64
- // argument, since the result cannot be greater than the value on the
- // left-hand side:
- //
- // Int32 % int => Int32
- // Int32 % Int32 => Int32
- // Int32 % Int64 => Int32
-
- IntX operator +(other) {
- if (other is Int64) {
- return this.toInt64() + other;
- }
- return new Int32(_i + _toInt(other));
- }
-
- IntX operator -(other) {
- if (other is Int64) {
- return this.toInt64() - other;
- }
- return new Int32(_i - _toInt(other));
- }
-
- Int32 operator -() => new Int32(-_i);
-
- IntX operator *(other) {
- if (other is Int64) {
- return this.toInt64() * other;
- }
- // TODO(rice) - optimize
- return (this.toInt64() * other).toInt32();
- }
-
- Int32 operator %(other) {
- if (other is Int64) {
- // Result will be Int32
- return (this.toInt64() % other).toInt32();
- }
- return new Int32(_i % _toInt(other));
- }
-
- Int32 operator ~/(other) {
- if (other is Int64) {
- return (this.toInt64() ~/ other).toInt32();
- }
- return new Int32(_i ~/ _toInt(other));
- }
-
- Int32 remainder(other) {
- if (other is Int64) {
- Int64 t = this.toInt64();
- return (t - (t ~/ other) * other).toInt32();
- }
- return this - (this ~/ other) * other;
- }
-
- Int32 operator &(other) {
- if (other is Int64) {
- return (this.toInt64() & other).toInt32();
- }
- return new Int32(_i & _toInt(other));
- }
-
- Int32 operator |(other) {
- if (other is Int64) {
- return (this.toInt64() | other).toInt32();
- }
- return new Int32(_i | _toInt(other));
- }
-
- Int32 operator ^(other) {
- if (other is Int64) {
- return (this.toInt64() ^ other).toInt32();
- }
- return new Int32(_i ^ _toInt(other));
- }
-
- Int32 operator ~() => new Int32(~_i);
-
- Int32 operator <<(int n) {
- if (n < 0) {
- throw new ArgumentError(n);
- }
- n &= 31;
- return new Int32(_i << n);
- }
-
- Int32 operator >>(int n) {
- if (n < 0) {
- throw new ArgumentError(n);
- }
- n &= 31;
- int value;
- if (_i >= 0) {
- value = _i >> n;
- } else {
- value = (_i >> n) | (0xffffffff << (32 - n));
- }
- return new Int32(value);
- }
-
- Int32 shiftRightUnsigned(int n) {
- if (n < 0) {
- throw new ArgumentError(n);
- }
- n &= 31;
- int value;
- if (_i >= 0) {
- value = _i >> n;
- } else {
- value = (_i >> n) & ((1 << (32 - n)) - 1);
- }
- return new Int32(value);
- }
-
- /**
- * Returns [:true:] if this [Int32] has the same numeric value as the
- * given object. The argument may be an [int] or an [IntX].
- */
- bool operator ==(other) {
- if (other is Int32) {
- return _i == other._i;
- } else if (other is Int64) {
- return this.toInt64() == other;
- } else if (other is int) {
- return _i == other;
- }
- return false;
- }
-
- int compareTo(IntX other) {
- if (other is Int64) {
- return this.toInt64().compareTo(other);
- }
- return _i.compareTo(_toInt(other));
- }
-
- bool operator <(other) {
- if (other is Int64) {
- return this.toInt64() < other;
- }
- return _i < _toInt(other);
- }
-
- bool operator <=(other) {
- if (other is Int64) {
- return this.toInt64() <= other;
- }
- return _i <= _toInt(other);
- }
-
- bool operator >(other) {
- if (other is Int64) {
- return this.toInt64() > other;
- }
- return _i > _toInt(other);
- }
-
- bool operator >=(other) {
- if (other is Int64) {
- return this.toInt64() >= other;
- }
- return _i >= _toInt(other);
- }
-
- bool get isEven => (_i & 0x1) == 0;
- bool get isMaxValue => _i == 2147483647;
- bool get isMinValue => _i == -2147483648;
- bool get isNegative => _i < 0;
- bool get isOdd => (_i & 0x1) == 1;
- bool get isZero => _i == 0;
- int get bitLength => _i.bitLength;
-
- int get hashCode => _i;
-
- Int32 abs() => _i < 0 ? new Int32(-_i) : this;
-
- Int32 clamp(lowerLimit, upperLimit) {
- if (this < lowerLimit) {
- if (lowerLimit is IntX) return lowerLimit.toInt32();
- if (lowerLimit is int) return new Int32(lowerLimit);
- throw new ArgumentError(lowerLimit);
- } else if (this > upperLimit) {
- if (upperLimit is IntX) return upperLimit.toInt32();
- if (upperLimit is int) return new Int32(upperLimit);
- throw new ArgumentError(upperLimit);
- }
- return this;
- }
-
- int numberOfLeadingZeros() => _numberOfLeadingZeros(_i);
- int numberOfTrailingZeros() => _numberOfTrailingZeros(_i);
-
- Int32 toSigned(int width) {
- if (width < 1 || width > 32) throw new RangeError.range(width, 1, 32);
- return new Int32(_i.toSigned(width));
- }
-
- Int32 toUnsigned(int width) {
- if (width < 0 || width > 32) throw new RangeError.range(width, 0, 32);
- return new Int32(_i.toUnsigned(width));
- }
-
- List<int> toBytes() {
- List<int> result = new List<int>(4);
- result[0] = _i & 0xff;
- result[1] = (_i >> 8) & 0xff;
- result[2] = (_i >> 16) & 0xff;
- result[3] = (_i >> 24) & 0xff;
- return result;
- }
-
- double toDouble() => _i.toDouble();
- int toInt() => _i;
- Int32 toInt32() => this;
- Int64 toInt64() => new Int64(_i);
-
- String toString() => _i.toString();
- String toHexString() => _i.toRadixString(16);
- String toRadixString(int radix) => _i.toRadixString(radix);
-}
diff --git a/pkg/fixnum/lib/src/int64.dart b/pkg/fixnum/lib/src/int64.dart
deleted file mode 100644
index 7770eb1..0000000
--- a/pkg/fixnum/lib/src/int64.dart
+++ /dev/null
@@ -1,1002 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of fixnum;
-
-/**
- * An immutable 64-bit signed integer, in the range [-2^63, 2^63 - 1].
- * Arithmetic operations may overflow in order to maintain this range.
- */
-class Int64 implements IntX {
-
- // A 64-bit integer is represented internally as three non-negative
- // integers, storing the 22 low, 22 middle, and 20 high bits of the
- // 64-bit value. _l (low) and _m (middle) are in the range
- // [0, 2^22 - 1] and _h (high) is in the range [0, 2^20 - 1].
- //
- // The values being assigned to _l, _m and _h in initialization are masked to
- // force them into the above ranges. Sometimes we know that the value is a
- // small non-negative integer but the dart2js compiler can't infer that, so a
- // few of the masking operations are not needed for correctness but are
- // helpful for dart2js code quality.
-
- final int _l, _m, _h;
-
- // Note: several functions require _BITS == 22 -- do not change this value.
- static const int _BITS = 22;
- static const int _BITS01 = 44; // 2 * _BITS
- static const int _BITS2 = 20; // 64 - _BITS01
- static const int _MASK = 4194303; // (1 << _BITS) - 1
- static const int _MASK2 = 1048575; // (1 << _BITS2) - 1
- static const int _SIGN_BIT = 19; // _BITS2 - 1
- static const int _SIGN_BIT_MASK = 1 << _SIGN_BIT;
-
- /**
- * The maximum positive value attainable by an [Int64], namely
- * 9,223,372,036,854,775,807.
- */
- static const Int64 MAX_VALUE = const Int64._bits(_MASK, _MASK, _MASK2 >> 1);
-
- /**
- * The minimum positive value attainable by an [Int64], namely
- * -9,223,372,036,854,775,808.
- */
- static const Int64 MIN_VALUE = const Int64._bits(0, 0, _SIGN_BIT_MASK);
-
- /**
- * An [Int64] constant equal to 0.
- */
- static const Int64 ZERO = const Int64._bits(0, 0, 0);
-
- /**
- * An [Int64] constant equal to 1.
- */
- static const Int64 ONE = const Int64._bits(1, 0, 0);
-
- /**
- * An [Int64] constant equal to 2.
- */
- static const Int64 TWO = const Int64._bits(2, 0, 0);
-
- /**
- * Constructs an [Int64] with a given bitwise representation. No validation
- * is performed.
- */
- const Int64._bits(int this._l, int this._m, int this._h);
-
- /**
- * Parses a [String] in a given [radix] between 2 and 36 and returns an
- * [Int64].
- */
- static Int64 parseRadix(String s, int radix) {
- return _parseRadix(s, Int32._validateRadix(radix));
- }
-
- static Int64 _parseRadix(String s, int radix) {
- int i = 0;
- bool negative = false;
- if (s[0] == '-') {
- negative = true;
- i++;
- }
- int d0 = 0, d1 = 0, d2 = 0; // low, middle, high components.
- for (; i < s.length; i++) {
- int c = s.codeUnitAt(i);
- int digit = Int32._decodeDigit(c);
- if (digit < 0 || digit >= radix) {
- throw new FormatException("Non-radix char code: $c");
- }
-
- // [radix] and [digit] are at most 6 bits, component is 22, so we can
- // multiply and add within 30 bit temporary values.
- d0 = d0 * radix + digit;
- int carry = d0 >> _BITS;
- d0 = _MASK & d0;
-
- d1 = d1 * radix + carry;
- carry = d1 >> _BITS;
- d1 = _MASK & d1;
-
- d2 = d2 * radix + carry;
- d2 = _MASK2 & d2;
- }
-
- if (negative) return _negate(d0, d1, d2);
-
- return Int64._masked(d0, d1, d2);
- }
-
- /**
- * Parses a decimal [String] and returns an [Int64].
- */
- static Int64 parseInt(String s) => _parseRadix(s, 10);
-
- /**
- * Parses a hexadecimal [String] and returns an [Int64].
- */
- static Int64 parseHex(String s) => _parseRadix(s, 16);
-
- //
- // Public constructors
- //
-
- /**
- * Constructs an [Int64] with a given [int] value; zero by default.
- */
- factory Int64([int value=0]) {
- int v0 = 0, v1 = 0, v2 = 0;
- bool negative = false;
- if (value < 0) {
- negative = true;
- value = -value - 1;
- }
- // Avoid using bitwise operations that in JavaScript coerce their input to
- // 32 bits.
- v2 = value ~/ 17592186044416; // 2^44
- value -= v2 * 17592186044416;
- v1 = value ~/ 4194304; // 2^22
- value -= v1 * 4194304;
- v0 = value;
-
- if (negative) {
- v0 = ~v0;
- v1 = ~v1;
- v2 = ~v2;
- }
- return Int64._masked(v0, v1, v2);
- }
-
- factory Int64.fromBytes(List<int> bytes) {
- int top = bytes[7] & 0xff;
- top <<= 8;
- top |= bytes[6] & 0xff;
- top <<= 8;
- top |= bytes[5] & 0xff;
- top <<= 8;
- top |= bytes[4] & 0xff;
-
- int bottom = bytes[3] & 0xff;
- bottom <<= 8;
- bottom |= bytes[2] & 0xff;
- bottom <<= 8;
- bottom |= bytes[1] & 0xff;
- bottom <<= 8;
- bottom |= bytes[0] & 0xff;
-
- return new Int64.fromInts(top, bottom);
- }
-
- factory Int64.fromBytesBigEndian(List<int> bytes) {
- int top = bytes[0] & 0xff;
- top <<= 8;
- top |= bytes[1] & 0xff;
- top <<= 8;
- top |= bytes[2] & 0xff;
- top <<= 8;
- top |= bytes[3] & 0xff;
-
- int bottom = bytes[4] & 0xff;
- bottom <<= 8;
- bottom |= bytes[5] & 0xff;
- bottom <<= 8;
- bottom |= bytes[6] & 0xff;
- bottom <<= 8;
- bottom |= bytes[7] & 0xff;
-
- return new Int64.fromInts(top, bottom);
- }
-
- /**
- * Constructs an [Int64] from a pair of 32-bit integers having the value
- * [:((top & 0xffffffff) << 32) | (bottom & 0xffffffff):].
- */
- factory Int64.fromInts(int top, int bottom) {
- top &= 0xffffffff;
- bottom &= 0xffffffff;
- int d0 = _MASK & bottom;
- int d1 = ((0xfff & top) << 10) | (0x3ff & (bottom >> _BITS));
- int d2 = _MASK2 & (top >> 12);
- return Int64._masked(d0, d1, d2);
- }
-
- // Returns the [Int64] representation of the specified value. Throws
- // [ArgumentError] for non-integer arguments.
- static Int64 _promote(value) {
- if (value is Int64) {
- return value;
- } else if (value is int) {
- return new Int64(value);
- } else if (value is Int32) {
- return value.toInt64();
- }
- throw new ArgumentError.value(value);
- }
-
- Int64 operator +(other) {
- Int64 o = _promote(other);
- int sum0 = _l + o._l;
- int sum1 = _m + o._m + (sum0 >> _BITS);
- int sum2 = _h + o._h + (sum1 >> _BITS);
- return Int64._masked(sum0, sum1, sum2);
- }
-
- Int64 operator -(other) {
- Int64 o = _promote(other);
- return _sub(_l, _m, _h, o._l, o._m, o._h);
- }
-
- Int64 operator -() => _negate(_l, _m, _h);
-
- Int64 operator *(other) {
- Int64 o = _promote(other);
-
- // Grab 13-bit chunks.
- int a0 = _l & 0x1fff;
- int a1 = (_l >> 13) | ((_m & 0xf) << 9);
- int a2 = (_m >> 4) & 0x1fff;
- int a3 = (_m >> 17) | ((_h & 0xff) << 5);
- int a4 = (_h & 0xfff00) >> 8;
-
- int b0 = o._l & 0x1fff;
- int b1 = (o._l >> 13) | ((o._m & 0xf) << 9);
- int b2 = (o._m >> 4) & 0x1fff;
- int b3 = (o._m >> 17) | ((o._h & 0xff) << 5);
- int b4 = (o._h & 0xfff00) >> 8;
-
- // Compute partial products.
- // Optimization: if b is small, avoid multiplying by parts that are 0.
- int p0 = a0 * b0; // << 0
- int p1 = a1 * b0; // << 13
- int p2 = a2 * b0; // << 26
- int p3 = a3 * b0; // << 39
- int p4 = a4 * b0; // << 52
-
- if (b1 != 0) {
- p1 += a0 * b1;
- p2 += a1 * b1;
- p3 += a2 * b1;
- p4 += a3 * b1;
- }
- if (b2 != 0) {
- p2 += a0 * b2;
- p3 += a1 * b2;
- p4 += a2 * b2;
- }
- if (b3 != 0) {
- p3 += a0 * b3;
- p4 += a1 * b3;
- }
- if (b4 != 0) {
- p4 += a0 * b4;
- }
-
- // Accumulate into 22-bit chunks:
- // .........................................c10|...................c00|
- // |....................|..................xxxx|xxxxxxxxxxxxxxxxxxxxxx| p0
- // |....................|......................|......................|
- // |....................|...................c11|......c01.............|
- // |....................|....xxxxxxxxxxxxxxxxxx|xxxxxxxxx.............| p1
- // |....................|......................|......................|
- // |.................c22|...............c12....|......................|
- // |..........xxxxxxxxxx|xxxxxxxxxxxxxxxxxx....|......................| p2
- // |....................|......................|......................|
- // |.................c23|..c13.................|......................|
- // |xxxxxxxxxxxxxxxxxxxx|xxxxx.................|......................| p3
- // |....................|......................|......................|
- // |.........c24........|......................|......................|
- // |xxxxxxxxxxxx........|......................|......................| p4
-
- int c00 = p0 & 0x3fffff;
- int c01 = (p1 & 0x1ff) << 13;
- int c0 = c00 + c01;
-
- int c10 = p0 >> 22;
- int c11 = p1 >> 9;
- int c12 = (p2 & 0x3ffff) << 4;
- int c13 = (p3 & 0x1f) << 17;
- int c1 = c10 + c11 + c12 + c13;
-
- int c22 = p2 >> 18;
- int c23 = p3 >> 5;
- int c24 = (p4 & 0xfff) << 8;
- int c2 = c22 + c23 + c24;
-
- // Propagate high bits from c0 -> c1, c1 -> c2.
- c1 += c0 >> _BITS;
- c2 += c1 >> _BITS;
-
- return Int64._masked(c0, c1, c2);
- }
-
- Int64 operator %(other) => _divide(this, other, _RETURN_MOD);
-
- Int64 operator ~/(other) => _divide(this, other, _RETURN_DIV);
-
- Int64 remainder(other) => _divide(this, other, _RETURN_REM);
-
- Int64 operator &(other) {
- Int64 o = _promote(other);
- int a0 = _l & o._l;
- int a1 = _m & o._m;
- int a2 = _h & o._h;
- return Int64._masked(a0, a1, a2);
- }
-
- Int64 operator |(other) {
- Int64 o = _promote(other);
- int a0 = _l | o._l;
- int a1 = _m | o._m;
- int a2 = _h | o._h;
- return Int64._masked(a0, a1, a2);
- }
-
- Int64 operator ^(other) {
- Int64 o = _promote(other);
- int a0 = _l ^ o._l;
- int a1 = _m ^ o._m;
- int a2 = _h ^ o._h;
- return Int64._masked(a0, a1, a2);
- }
-
- Int64 operator ~() {
- return Int64._masked(~_l, ~_m, ~_h);
- }
-
- Int64 operator <<(int n) {
- if (n < 0) {
- throw new ArgumentError.value(n);
- }
- n &= 63;
-
- int res0, res1, res2;
- if (n < _BITS) {
- res0 = _l << n;
- res1 = (_m << n) | (_l >> (_BITS - n));
- res2 = (_h << n) | (_m >> (_BITS - n));
- } else if (n < _BITS01) {
- res0 = 0;
- res1 = _l << (n - _BITS);
- res2 = (_m << (n - _BITS)) | (_l >> (_BITS01 - n));
- } else {
- res0 = 0;
- res1 = 0;
- res2 = _l << (n - _BITS01);
- }
-
- return Int64._masked(res0, res1, res2);
- }
-
- Int64 operator >>(int n) {
- if (n < 0) {
- throw new ArgumentError.value(n);
- }
- n &= 63;
-
- int res0, res1, res2;
-
- // Sign extend h(a).
- int a2 = _h;
- bool negative = (a2 & _SIGN_BIT_MASK) != 0;
- if (negative && _MASK > _MASK2) {
- // Add extra one bits on the left so the sign gets shifted into the wider
- // lower words.
- a2 += (_MASK - _MASK2);
- }
-
- if (n < _BITS) {
- res2 = _shiftRight(a2, n);
- if (negative) {
- res2 |= _MASK2 & ~(_MASK2 >> n);
- }
- res1 = _shiftRight(_m, n) | (a2 << (_BITS - n));
- res0 = _shiftRight(_l, n) | (_m << (_BITS - n));
- } else if (n < _BITS01) {
- res2 = negative ? _MASK2 : 0;
- res1 = _shiftRight(a2, n - _BITS);
- if (negative) {
- res1 |= _MASK & ~(_MASK >> (n - _BITS));
- }
- res0 = _shiftRight(_m, n - _BITS) | (a2 << (_BITS01 - n));
- } else {
- res2 = negative ? _MASK2 : 0;
- res1 = negative ? _MASK : 0;
- res0 = _shiftRight(a2, n - _BITS01);
- if (negative) {
- res0 |= _MASK & ~(_MASK >> (n - _BITS01));
- }
- }
-
- return Int64._masked(res0, res1, res2);
- }
-
- Int64 shiftRightUnsigned(int n) {
- if (n < 0) {
- throw new ArgumentError.value(n);
- }
- n &= 63;
-
- int res0, res1, res2;
- int a2 = _MASK2 & _h; // Ensure a2 is positive.
- if (n < _BITS) {
- res2 = a2 >> n;
- res1 = (_m >> n) | (a2 << (_BITS - n));
- res0 = (_l >> n) | (_m << (_BITS - n));
- } else if (n < _BITS01) {
- res2 = 0;
- res1 = a2 >> (n - _BITS);
- res0 = (_m >> (n - _BITS)) | (_h << (_BITS01 - n));
- } else {
- res2 = 0;
- res1 = 0;
- res0 = a2 >> (n - _BITS01);
- }
-
- return Int64._masked(res0, res1, res2);
- }
-
- /**
- * Returns [:true:] if this [Int64] has the same numeric value as the
- * given object. The argument may be an [int] or an [IntX].
- */
- bool operator ==(other) {
- Int64 o;
- if (other is Int64) {
- o = other;
- } else if (other is int) {
- if (_h == 0 && _m == 0) return _l == other;
- // Since we know one of [_h] or [_m] is non-zero, if [other] fits in the
- // low word then it can't be numerically equal.
- if ((_MASK & other) == other) return false;
- o = new Int64(other);
- } else if (other is Int32) {
- o = other.toInt64();
- }
- if (o != null) {
- return _l == o._l && _m == o._m && _h == o._h;
- }
- return false;
- }
-
- int compareTo(IntX other) =>_compareTo(other);
-
- int _compareTo(other) {
- Int64 o = _promote(other);
- int signa = _h >> (_BITS2 - 1);
- int signb = o._h >> (_BITS2 - 1);
- if (signa != signb) {
- return signa == 0 ? 1 : -1;
- }
- if (_h > o._h) {
- return 1;
- } else if (_h < o._h) {
- return -1;
- }
- if (_m > o._m) {
- return 1;
- } else if (_m < o._m) {
- return -1;
- }
- if (_l > o._l) {
- return 1;
- } else if (_l < o._l) {
- return -1;
- }
- return 0;
- }
-
- bool operator <(other) => _compareTo(other) < 0;
- bool operator <=(other) => _compareTo(other) <= 0;
- bool operator >(other) => this._compareTo(other) > 0;
- bool operator >=(other) => _compareTo(other) >= 0;
-
- bool get isEven => (_l & 0x1) == 0;
- bool get isMaxValue => (_h == _MASK2 >> 1) && _m == _MASK && _l == _MASK;
- bool get isMinValue => _h == _SIGN_BIT_MASK && _m == 0 && _l == 0;
- bool get isNegative => (_h & _SIGN_BIT_MASK) != 0;
- bool get isOdd => (_l & 0x1) == 1;
- bool get isZero => _h == 0 && _m == 0 && _l == 0;
-
- int get bitLength {
- if (isZero) return 0;
- int a0 = _l, a1 = _m, a2 = _h;
- if (isNegative) {
- a0 = _MASK & ~a0;
- a1 = _MASK & ~a1;
- a2 = _MASK2 & ~a2;
- }
- if (a2 != 0) return _BITS01 + a2.bitLength;
- if (a1 != 0) return _BITS + a1.bitLength;
- return a0.bitLength;
- }
-
- /**
- * Returns a hash code based on all the bits of this [Int64].
- */
- int get hashCode {
- // TODO(sra): Should we ensure that hashCode values match corresponding int?
- // i.e. should `new Int64(x).hashCode == x.hashCode`?
- int bottom = ((_m & 0x3ff) << _BITS) | _l;
- int top = (_h << 12) | ((_m >> 10) & 0xfff);
- return bottom ^ top;
- }
-
- Int64 abs() {
- return this.isNegative ? -this : this;
- }
-
- Int64 clamp(lowerLimit, upperLimit) {
- Int64 lower = _promote(lowerLimit);
- Int64 upper = _promote(upperLimit);
- if (this < lower) return lower;
- if (this > upper) return upper;
- return this;
- }
-
- /**
- * Returns the number of leading zeros in this [Int64] as an [int]
- * between 0 and 64.
- */
- int numberOfLeadingZeros() {
- int b2 = Int32._numberOfLeadingZeros(_h);
- if (b2 == 32) {
- int b1 = Int32._numberOfLeadingZeros(_m);
- if (b1 == 32) {
- return Int32._numberOfLeadingZeros(_l) + 32;
- } else {
- return b1 + _BITS2 - (32 - _BITS);
- }
- } else {
- return b2 - (32 - _BITS2);
- }
- }
-
- /**
- * Returns the number of trailing zeros in this [Int64] as an [int]
- * between 0 and 64.
- */
- int numberOfTrailingZeros() {
- int zeros = Int32._numberOfTrailingZeros(_l);
- if (zeros < 32) {
- return zeros;
- }
-
- zeros = Int32._numberOfTrailingZeros(_m);
- if (zeros < 32) {
- return _BITS + zeros;
- }
-
- zeros = Int32._numberOfTrailingZeros(_h);
- if (zeros < 32) {
- return _BITS01 + zeros;
- }
- // All zeros
- return 64;
- }
-
- Int64 toSigned(int width) {
- if (width < 1 || width > 64) throw new RangeError.range(width, 1, 64);
- if (width > _BITS01) {
- return Int64._masked(_l, _m, _h.toSigned(width - _BITS01));
- } else if (width > _BITS) {
- int m = _m.toSigned(width - _BITS);
- return m.isNegative
- ? Int64._masked(_l, m, _MASK2)
- : Int64._masked(_l, m, 0); // Masking for type inferrer.
- } else {
- int l = _l.toSigned(width);
- return l.isNegative
- ? Int64._masked(l, _MASK, _MASK2)
- : Int64._masked(l, 0, 0); // Masking for type inferrer.
- }
- }
-
- Int64 toUnsigned(int width) {
- if (width < 0 || width > 64) throw new RangeError.range(width, 0, 64);
- if (width > _BITS01) {
- int h = _h.toUnsigned(width - _BITS01);
- return Int64._masked(_l, _m, h);
- } else if (width > _BITS) {
- int m = _m.toUnsigned(width - _BITS);
- return Int64._masked(_l, m, 0);
- } else {
- int l = _l.toUnsigned(width);
- return Int64._masked(l, 0, 0);
- }
- }
-
- List<int> toBytes() {
- List<int> result = new List<int>(8);
- result[0] = _l & 0xff;
- result[1] = (_l >> 8) & 0xff;
- result[2] = ((_m << 6) & 0xfc) | ((_l >> 16) & 0x3f);
- result[3] = (_m >> 2) & 0xff;
- result[4] = (_m >> 10) & 0xff;
- result[5] = ((_h << 4) & 0xf0) | ((_m >> 18) & 0xf);
- result[6] = (_h >> 4) & 0xff;
- result[7] = (_h >> 12) & 0xff;
- return result;
- }
-
- double toDouble() => toInt().toDouble();
-
- int toInt() {
- int l = _l;
- int m = _m;
- int h = _h;
- // In the sum we add least significant to most significant so that in
- // JavaScript double arithmetic rounding occurs on only the last addition.
- if ((_h & _SIGN_BIT_MASK) != 0) {
- l = _MASK & ~_l;
- m = _MASK & ~_m;
- h = _MASK2 & ~_h;
- return -((1 + l) + (4194304 * m) + (17592186044416 * h));
- } else {
- return l + (4194304 * m) + (17592186044416 * h);
- }
- }
-
- /**
- * Returns an [Int32] containing the low 32 bits of this [Int64].
- */
- Int32 toInt32() {
- return new Int32(((_m & 0x3ff) << _BITS) | _l);
- }
-
- /**
- * Returns [this].
- */
- Int64 toInt64() => this;
-
- /**
- * Returns the value of this [Int64] as a decimal [String].
- */
- String toString() => _toRadixString(10);
-
- // TODO(rice) - Make this faster by avoiding arithmetic.
- String toHexString() {
- if (isZero) return "0";
- Int64 x = this;
- String hexStr = "";
- while (!x.isZero) {
- int digit = x._l & 0xf;
- hexStr = "${_hexDigit(digit)}$hexStr";
- x = x.shiftRightUnsigned(4);
- }
- return hexStr;
- }
-
- String toRadixString(int radix) {
- return _toRadixString(Int32._validateRadix(radix));
- }
-
- String _toRadixString(int radix) {
- int d0 = _l;
- int d1 = _m;
- int d2 = _h;
-
- if (d0 == 0 && d1 == 0 && d2 == 0) return '0';
-
- String sign = '';
- if ((d2 & _SIGN_BIT_MASK) != 0) {
- sign = '-';
-
- // Negate in-place.
- d0 = 0 - d0;
- int borrow = (d0 >> _BITS) & 1;
- d0 &= _MASK;
- d1 = 0 - d1 - borrow;
- borrow = (d1 >> _BITS) & 1;
- d1 &= _MASK;
- d2 = 0 - d2 - borrow;
- d2 &= _MASK2;
- // d2, d1, d0 now are an unsigned 64 bit integer for MIN_VALUE and an
- // unsigned 63 bit integer for other values.
- }
-
- // Rearrange components into five components where all but the most
- // significant are 10 bits wide.
- //
- // d4, d3, d4, d1, d0: 24 + 10 + 10 + 10 + 10 bits
- //
- // The choice of 10 bits allows a remainder of 20 bits to be scaled by 10
- // bits and added during division while keeping all intermediate values
- // within 30 bits (unsigned small integer range for 32 bit implementations
- // of Dart VM and V8).
- //
- // 6 6 5 4 3 2 1
- // 3210987654321098765432109876543210987654321098765432109876543210
- // [--------d2--------][---------d1---------][---------d0---------]
- // -->
- // [----------d4----------][---d3---][---d2---][---d1---][---d0---]
-
-
- int d4 = (d2 << 4) | (d1 >> 18);
- int d3 = (d1 >> 8) & 0x3ff;
- d2 = ((d1 << 2) | (d0 >> 20)) & 0x3ff;
- d1 = (d0 >> 10) & 0x3ff;
- d0 = d0 & 0x3ff;
-
- int fatRadix = _fatRadixTable[radix];
-
- // Generate chunks of digits. In radix 10, generate 6 digits per chunk.
- //
- // This loop generates at most 3 chunks, so we store the chunks in locals
- // rather than a list. We are trying to generate digits 20 bits at a time
- // until we have only 30 bits left. 20 + 20 + 30 > 64 would imply that we
- // need only two chunks, but radix values 17-19 and 33-36 generate only 15
- // or 16 bits per iteration, so sometimes the third chunk is needed.
-
- String chunk1 = "", chunk2 = "", chunk3 = "";
-
- while (!(d4 == 0 && d3 == 0)) {
- int q = d4 ~/ fatRadix;
- int r = d4 - q * fatRadix;
- d4 = q;
- d3 += r << 10;
-
- q = d3 ~/ fatRadix;
- r = d3 - q * fatRadix;
- d3 = q;
- d2 += r << 10;
-
- q = d2 ~/ fatRadix;
- r = d2 - q * fatRadix;
- d2 = q;
- d1 += r << 10;
-
- q = d1 ~/ fatRadix;
- r = d1 - q * fatRadix;
- d1 = q;
- d0 += r << 10;
-
- q = d0 ~/ fatRadix;
- r = d0 - q * fatRadix;
- d0 = q;
-
- assert(chunk3 == "");
- chunk3 = chunk2;
- chunk2 = chunk1;
- // Adding [fatRadix] Forces an extra digit which we discard to get a fixed
- // width. E.g. (1000000 + 123) -> "1000123" -> "000123". An alternative
- // would be to pad to the left with zeroes.
- chunk1 = (fatRadix + r).toRadixString(radix).substring(1);
- }
- int residue = (d2 << 20) + (d1 << 10) + d0;
- String leadingDigits = residue == 0 ? '' : residue.toRadixString(radix);
- return '$sign$leadingDigits$chunk1$chunk2$chunk3';
- }
-
- // Table of 'fat' radix values. Each entry for index `i` is the largest power
- // of `i` whose remainder fits in 20 bits.
- static const _fatRadixTable = const <int>[
- 0,
- 0,
- 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2
- * 2,
- 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3,
- 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4,
- 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
- 6 * 6 * 6 * 6 * 6 * 6 * 6,
- 7 * 7 * 7 * 7 * 7 * 7 * 7,
- 8 * 8 * 8 * 8 * 8 * 8,
- 9 * 9 * 9 * 9 * 9 * 9,
- 10 * 10 * 10 * 10 * 10 * 10,
- 11 * 11 * 11 * 11 * 11,
- 12 * 12 * 12 * 12 * 12,
- 13 * 13 * 13 * 13 * 13,
- 14 * 14 * 14 * 14 * 14,
- 15 * 15 * 15 * 15 * 15,
- 16 * 16 * 16 * 16 * 16,
- 17 * 17 * 17 * 17,
- 18 * 18 * 18 * 18,
- 19 * 19 * 19 * 19,
- 20 * 20 * 20 * 20,
- 21 * 21 * 21 * 21,
- 22 * 22 * 22 * 22,
- 23 * 23 * 23 * 23,
- 24 * 24 * 24 * 24,
- 25 * 25 * 25 * 25,
- 26 * 26 * 26 * 26,
- 27 * 27 * 27 * 27,
- 28 * 28 * 28 * 28,
- 29 * 29 * 29 * 29,
- 30 * 30 * 30 * 30,
- 31 * 31 * 31 * 31,
- 32 * 32 * 32 * 32,
- 33 * 33 * 33,
- 34 * 34 * 34,
- 35 * 35 * 35,
- 36 * 36 * 36
- ];
-
- String toDebugString() {
- return "Int64[_l=$_l, _m=$_m, _h=$_h]";
- }
-
-
- static Int64 _masked(int a0, int a1, int a2) =>
- new Int64._bits(_MASK & a0, _MASK & a1, _MASK2 & a2);
-
- static Int64 _sub(int a0, int a1, int a2, int b0, int b1, int b2) {
- int diff0 = a0 - b0;
- int diff1 = a1 - b1 - ((diff0 >> _BITS) & 1);
- int diff2 = a2 - b2 - ((diff1 >> _BITS) & 1);
- return _masked(diff0, diff1, diff2);
- }
-
- static Int64 _negate(int b0, int b1, int b2) {
- return _sub(0, 0, 0, b0, b1, b2);
- }
-
- String _hexDigit(int digit) => "0123456789ABCDEF"[digit];
-
- // Work around dart2js bugs with negative arguments to '>>' operator.
- static int _shiftRight(int x, int n) {
- if (x >= 0) {
- return x >> n;
- } else {
- int shifted = x >> n;
- if (shifted >= 0x80000000) {
- shifted -= 4294967296;
- }
- return shifted;
- }
- }
-
-
- // Implementation of '~/', '%' and 'remainder'.
-
- static Int64 _divide(Int64 a, other, int what) {
- Int64 b = _promote(other);
- if (b.isZero) {
- throw new IntegerDivisionByZeroException();
- }
- if (a.isZero) return ZERO;
-
- bool aNeg = a.isNegative;
- bool bNeg = b.isNegative;
- a = a.abs();
- b = b.abs();
-
- int a0 = a._l;
- int a1 = a._m;
- int a2 = a._h;
-
- int b0 = b._l;
- int b1 = b._m;
- int b2 = b._h;
- return _divideHelper(a0, a1, a2, aNeg, b0, b1, b2, bNeg, what);
- }
-
- static const _RETURN_DIV = 1;
- static const _RETURN_REM = 2;
- static const _RETURN_MOD = 3;
-
- static _divideHelper(
- // up to 64 bits unsigned in a2/a1/a0 and b2/b1/b0
- int a0, int a1, int a2, bool aNeg, // input A.
- int b0, int b1, int b2, bool bNeg, // input B.
- int what) {
- int q0 = 0, q1 = 0, q2 = 0; // result Q.
- int r0 = 0, r1 = 0, r2 = 0; // result R.
-
- if (b2 == 0 && b1 == 0 && b0 < (1 << (30 - _BITS))) {
- // Small divisor can be handled by single-digit division within Smi range.
- //
- // Handling small divisors here helps the estimate version below by
- // handling cases where the estimate is off by more than a small amount.
-
- q2 = a2 ~/ b0;
- int carry = a2 - q2 * b0;
- int d1 = a1 + (carry << _BITS);
- q1 = d1 ~/ b0;
- carry = d1 - q1 * b0;
- int d0 = a0 + (carry << _BITS);
- q0 = d0 ~/ b0;
- r0 = d0 - q0 * b0;
- } else {
- // Approximate Q = A ~/ B and R = A - Q * B using doubles.
-
- // The floating point approximation is very close to the correct value
- // when floor(A/B) fits in fewer that 53 bits.
-
- // We use double arithmetic for intermediate values. Double arithmetic on
- // non-negative values is exact under the following conditions:
- //
- // - The values are integer values that fit in 53 bits.
- // - Dividing by powers of two (adjusts exponent only).
- // - Floor (zeroes bits with fractional weight).
-
- const double K2 = 17592186044416.0; // 2^44
- const double K1 = 4194304.0; // 2^22
-
- // Approximate double values for [a] and [b].
- double ad = a0 + K1 * a1 + K2 * a2;
- double bd = b0 + K1 * b1 + K2 * b2;
- // Approximate quotient.
- double qd = (ad / bd).floorToDouble();
-
- // Extract components of [qd] using double arithmetic.
- double q2d = (qd / K2).floorToDouble();
- qd = qd - K2 * q2d;
- double q1d = (qd / K1).floorToDouble();
- double q0d = qd - K1 * q1d;
- q2 = q2d.toInt();
- q1 = q1d.toInt();
- q0 = q0d.toInt();
-
- assert(q0 + K1 * q1 + K2 * q2 == (ad / bd).floorToDouble());
- assert(q2 == 0 || b2 == 0); // Q and B can't both be big since Q*B <= A.
-
- // P = Q * B, using doubles to hold intermediates.
- // We don't need all partial sums since Q*B <= A.
- double p0d = q0d * b0;
- double p0carry = (p0d / K1).floorToDouble();
- p0d = p0d - p0carry * K1;
- double p1d = q1d * b0 + q0d * b1 + p0carry;
- double p1carry = (p1d / K1).floorToDouble();
- p1d = p1d - p1carry * K1;
- double p2d = q2d * b0 + q1d * b1 + q0d * b2 + p1carry;
- assert(p2d <= _MASK2); // No partial sum overflow.
-
- // R = A - P
- int diff0 = a0 - p0d.toInt();
- int diff1 = a1 - p1d.toInt() - ((diff0 >> _BITS) & 1);
- int diff2 = a2 - p2d.toInt() - ((diff1 >> _BITS) & 1);
- r0 = _MASK & diff0;
- r1 = _MASK & diff1;
- r2 = _MASK2 & diff2;
-
- // while (R < 0 || R >= B)
- // adjust R towards [0, B)
- while (
- r2 >= _SIGN_BIT_MASK ||
- r2 > b2 ||
- (r2 == b2 && (r1 > b1 || (r1 == b1 && r0 >= b0)))) {
- // Direction multiplier for adjustment.
- int m = (r2 & _SIGN_BIT_MASK) == 0 ? 1 : -1;
- // R = R - B or R = R + B
- int d0 = r0 - m * b0;
- int d1 = r1 - m * (b1 + ((d0 >> _BITS) & 1));
- int d2 = r2 - m * (b2 + ((d1 >> _BITS) & 1));
- r0 = _MASK & d0;
- r1 = _MASK & d1;
- r2 = _MASK2 & d2;
-
- // Q = Q + 1 or Q = Q - 1
- d0 = q0 + m;
- d1 = q1 + m * ((d0 >> _BITS) & 1);
- d2 = q2 + m * ((d1 >> _BITS) & 1);
- q0 = _MASK & d0;
- q1 = _MASK & d1;
- q2 = _MASK2 & d2;
- }
- }
-
- // 0 <= R < B
- assert(Int64.ZERO <= new Int64._bits(r0, r1, r2));
- assert(r2 < b2 || // Handles case where B = -(MIN_VALUE)
- new Int64._bits(r0, r1, r2) < new Int64._bits(b0, b1, b2));
-
- assert(what == _RETURN_DIV || what == _RETURN_MOD || what == _RETURN_REM);
- if (what == _RETURN_DIV) {
- if (aNeg != bNeg) return _negate(q0, q1, q2);
- return Int64._masked(q0, q1, q2); // Masking for type inferrer.
- }
-
- if (!aNeg) {
- return Int64._masked(r0, r1, r2); // Masking for type inferrer.
- }
-
- if (what == _RETURN_MOD) {
- if (r0 == 0 && r1 == 0 && r2 == 0) {
- return ZERO;
- } else {
- return _sub(b0, b1, b2, r0, r1, r2);
- }
- } else {
- return _negate(r0, r1, r2);
- }
- }
-}
diff --git a/pkg/fixnum/lib/src/intx.dart b/pkg/fixnum/lib/src/intx.dart
deleted file mode 100644
index f132aff..0000000
--- a/pkg/fixnum/lib/src/intx.dart
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of fixnum;
-
-/**
- * A fixed-precision integer.
- */
-abstract class IntX implements Comparable<IntX> {
-
- /** Addition operator. */
- IntX operator +(other);
-
- /** Subtraction operator. */
- IntX operator -(other);
-
- /**
- * Negate operator.
- *
- * Note that `-MIN_VALUE` is equal to `MIN_VALUE` due to overflow.
- */
- IntX operator -();
-
- /** Multiplication operator. */
- IntX operator *(other);
-
- /**
- * Euclidean modulo operator.
- *
- * Returns the remainder of the euclidean division. The euclidean division
- * of two integers `a` and `b` yields two integers `q` and `r` such that
- * `a == b * q + r` and `0 <= r < a.abs()`.
- */
- IntX operator %(other);
-
- /** Truncating division operator. */
- IntX operator ~/(other);
-
- /**
- * Returns the remainder of the truncating division of this integer by
- * [other].
- */
- IntX remainder(other);
-
- /** Bitwise and operator. */
- IntX operator &(other);
-
- /** Bitwise or operator. */
- IntX operator |(other);
-
- /** Bitwise xor operator. */
- IntX operator ^(other);
-
- /** Bitwise negate operator. */
- IntX operator ~();
-
- /**
- * Left bit-shift operator.
- *
- * Returns the result of shifting the bits of this integer by [shiftAmount]
- * bits to the left. Low-order bits are filled with zeros.
- */
- IntX operator <<(int shiftAmount);
-
- /**
- * Right bit-shift operator.
- *
- * Returns the result of shifting the bits of this integer by [shiftAmount]
- * bits to the right. High-order bits are filled with zero in the case where
- * this integer is positive, or one in the case where it is negative.
- */
- IntX operator >>(int shiftAmount);
-
- /**
- * Unsigned right-shift operator.
- *
- * Returns the result of shifting the bits of this integer by [shiftAmount]
- * bits to the right. High-order bits are filled with zeros.
- */
- IntX shiftRightUnsigned(int shiftAmount);
-
- /**
- * Returns `true` if and only if [other] is an int or IntX equal in
- * value to this integer.
- */
- bool operator ==(other);
-
- /** Relational less than operator. */
- bool operator <(other);
-
- /** Relational less than or equal to operator. */
- bool operator <=(other);
-
- /** Relational greater than operator. */
- bool operator >(other);
-
- /** Relational greater than or equal to operator. */
- bool operator >=(other);
-
- /** Returns `true` if and only if this integer is even. */
- bool get isEven;
-
- /**
- * Returns `true` if and only if this integer is the maximum signed value
- * that can be represented within its bit size.
- */
- bool get isMaxValue;
-
- /**
- * Returns `true` if and only if this integer is the minimum signed value
- * that can be represented within its bit size.
- */
- bool get isMinValue;
-
- /** Returns `true` if and only if this integer is less than zero. */
- bool get isNegative;
-
- /** Returns `true` if and only if this integer is odd. */
- bool get isOdd;
-
- /** Returns `true` if and only if this integer is zero. */
- bool get isZero;
-
- int get hashCode;
-
- /** Returns the absolute value of this integer. */
- IntX abs();
-
- /** Clamps this integer to be in the range [lowerLimit] - [upperLimit]. */
- IntX clamp(lowerLimit, upperLimit);
-
- /**
- * Returns the minimum number of bits required to store this integer.
- *
- * The number of bits excludes the sign bit, which gives the natural length
- * for non-negative (unsigned) values. Negative values are complemented to
- * return the bit position of the first bit that differs from the sign bit.
- *
- * To find the the number of bits needed to store the value as a signed value,
- * add one, i.e. use `x.bitLength + 1`.
- */
- int get bitLength;
-
- /**
- * Returns the number of high-order zeros in this integer's bit
- * representation.
- */
- int numberOfLeadingZeros();
-
- /**
- * Returns the number of low-order zeros in this integer's bit representation.
- */
- int numberOfTrailingZeros();
-
- /**
- * Returns the least significant [width] bits of this integer, extending the
- * highest retained bit to the sign. This is the same as truncating the value
- * to fit in [width] bits using an signed 2-s complement representation. The
- * returned value has the same bit value in all positions higher than [width].
- *
- * If the input value fits in [width] bits without truncation, the result is
- * the same as the input. The minimum width needed to avoid truncation of `x`
- * is `x.bitLength + 1`, i.e.
- *
- * x == x.toSigned(x.bitLength + 1);
- */
- IntX toSigned(int width);
-
- /**
- * Returns the least significant [width] bits of this integer as a
- * non-negative number (i.e. unsigned representation). The returned value has
- * zeros in all bit positions higher than [width].
- *
- * If the input fits in [width] bits without truncation, the result is the
- * same as the input. The minimum width needed to avoid truncation of `x` is
- * given by `x.bitLength`, i.e.
- *
- * x == x.toUnsigned(x.bitLength);
- */
- IntX toUnsigned(int width);
-
- /**
- * Returns a byte-sequence representation of this integer.
- *
- * Returns a list of int, starting with the least significant byte.
- */
- List<int> toBytes();
-
- /**
- * Returns the double representation of this integer.
- *
- * On some platforms, inputs with large absolute values (i.e., > 2^52) may
- * lose some of their low-order bits.
- */
- double toDouble();
-
- /**
- * Returns the int representation of this integer.
- *
- * On some platforms, inputs with large absolute values (i.e., > 2^52) may
- * lose some of their low-order bits.
- */
- int toInt();
-
- /**
- * Returns an Int32 representation of this integer.
- *
- * Narrower values are sign-extended and wider values have their high bits
- * truncated.
- */
- Int32 toInt32();
-
- /** Returns an Int64 representation of this integer. */
- Int64 toInt64();
-
- /**
- * Returns a string representing the value of this integer in decimal
- * notation; example: `'13'`.
- */
- String toString();
-
- /**
- * Returns a string representing the value of this integer in hexadecimal
- * notation; example: `'0xd'`.
- */
- String toHexString();
-
- /**
- * Returns a string representing the value of this integer in the given radix.
- *
- * [radix] must be an integer in the range 2 .. 16, inclusive.
- */
- String toRadixString(int radix);
-}
diff --git a/pkg/fixnum/pubspec.yaml b/pkg/fixnum/pubspec.yaml
deleted file mode 100644
index 3d3bdaf..0000000
--- a/pkg/fixnum/pubspec.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: fixnum
-version: 0.10.3
-author: Dart Team <misc@dartlang.org>
-description: Library for 32- and 64-bit fixed size integers.
-homepage: http://www.dartlang.org
-dev_dependencies:
- unittest: ">=0.9.0 <0.10.0"
-environment:
- sdk: ">=0.8.10+6 <2.0.0"
diff --git a/pkg/fixnum/test/int_32_test.dart b/pkg/fixnum/test/int_32_test.dart
deleted file mode 100644
index e5c8c5f..0000000
--- a/pkg/fixnum/test/int_32_test.dart
+++ /dev/null
@@ -1,365 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library Int32test;
-import 'package:fixnum/fixnum.dart';
-import 'package:unittest/unittest.dart';
-
-void main() {
- group("isX tests", () {
- test("isEven", () {
- expect((-Int32.ONE).isEven, false);
- expect(Int32.ZERO.isEven, true);
- expect(Int32.ONE.isEven, false);
- expect(Int32.TWO.isEven, true);
- });
- test("isMaxValue", () {
- expect(Int32.MIN_VALUE.isMaxValue, false);
- expect(Int32.ZERO.isMaxValue, false);
- expect(Int32.MAX_VALUE.isMaxValue, true);
- });
- test("isMinValue", () {
- expect(Int32.MIN_VALUE.isMinValue, true);
- expect(Int32.ZERO.isMinValue, false);
- expect(Int32.MAX_VALUE.isMinValue, false);
- });
- test("isNegative", () {
- expect(Int32.MIN_VALUE.isNegative, true);
- expect(Int32.ZERO.isNegative, false);
- expect(Int32.ONE.isNegative, false);
- });
- test("isOdd", () {
- expect((-Int32.ONE).isOdd, true);
- expect(Int32.ZERO.isOdd, false);
- expect(Int32.ONE.isOdd, true);
- expect(Int32.TWO.isOdd, false);
- });
- test("isZero", () {
- expect(Int32.MIN_VALUE.isZero, false);
- expect(Int32.ZERO.isZero, true);
- expect(Int32.MAX_VALUE.isZero, false);
- });
- test("bitLength", () {
- expect(new Int32(-2).bitLength, 1);
- expect((-Int32.ONE).bitLength, 0);
- expect(Int32.ZERO.bitLength, 0);
- expect(Int32.ONE.bitLength, 1);
- expect(new Int32(2).bitLength, 2);
- expect(Int32.MAX_VALUE.bitLength, 31);
- expect(Int32.MIN_VALUE.bitLength, 31);
- });
- });
-
- group("arithmetic operators", () {
- Int32 n1 = new Int32(1234);
- Int32 n2 = new Int32(9876);
- Int32 n3 = new Int32(-1234);
- Int32 n4 = new Int32(-9876);
-
- test("+", () {
- expect(n1 + n2, new Int32(11110));
- expect(n3 + n2, new Int32(8642));
- expect(n3 + n4, new Int32(-11110));
- expect(Int32.MAX_VALUE + 1, Int32.MIN_VALUE);
- expect(() => new Int32(17) + null, throws);
- });
-
- test("-", () {
- expect(n1 - n2, new Int32(-8642));
- expect(n3 - n2, new Int32(-11110));
- expect(n3 - n4, new Int32(8642));
- expect(Int32.MIN_VALUE - 1, Int32.MAX_VALUE);
- expect(() => new Int32(17) - null, throws);
- });
-
- test("unary -", () {
- expect(-n1, new Int32(-1234));
- expect(-Int32.ZERO, Int32.ZERO);
- });
-
- test("*", () {
- expect(n1 * n2, new Int32(12186984));
- expect(n2 * n3, new Int32(-12186984));
- expect(n3 * n3, new Int32(1522756));
- expect(n3 * n2, new Int32(-12186984));
- expect(new Int32(0x12345678) * new Int32(0x22222222),
- new Int32(-899716112));
- expect((new Int32(123456789) * new Int32(987654321)),
- new Int32(-67153019));
- expect(new Int32(0x12345678) * new Int64(0x22222222),
- new Int64.fromInts(0x026D60DC, 0xCA5F6BF0));
- expect((new Int32(123456789) * 987654321),
- new Int32(-67153019));
- expect(() => new Int32(17) * null, throws);
- });
-
- test("~/", () {
- expect(new Int32(829893893) ~/ new Int32(1919), new Int32(432461));
- expect(new Int32(0x12345678) ~/ new Int32(0x22),
- new Int32(0x12345678 ~/ 0x22));
- expect(new Int32(829893893) ~/ new Int64(1919), new Int32(432461));
- expect(new Int32(0x12345678) ~/ new Int64(0x22),
- new Int32(0x12345678 ~/ 0x22));
- expect(new Int32(829893893) ~/ 1919, new Int32(432461));
- expect(() => new Int32(17) ~/ Int32.ZERO, throws);
- expect(() => new Int32(17) ~/ null, throws);
- });
-
- test("%", () {
- expect(new Int32(0x12345678) % new Int32(0x22),
- new Int32(0x12345678 % 0x22));
- expect(new Int32(0x12345678) % new Int64(0x22),
- new Int32(0x12345678 % 0x22));
- expect(() => new Int32(17) % null, throws);
- });
-
- test("remainder", () {
- expect(new Int32(0x12345678).remainder(new Int32(0x22)),
- new Int32(0x12345678.remainder(0x22)));
- expect(new Int32(0x12345678).remainder(new Int32(-0x22)),
- new Int32(0x12345678.remainder(-0x22)));
- expect(new Int32(-0x12345678).remainder(new Int32(-0x22)),
- new Int32(-0x12345678.remainder(-0x22)));
- expect(new Int32(-0x12345678).remainder(new Int32(0x22)),
- new Int32(-0x12345678.remainder(0x22)));
- expect(new Int32(0x12345678).remainder(new Int64(0x22)),
- new Int32(0x12345678.remainder(0x22)));
- expect(() => new Int32(17).remainder(null), throws);
- });
-
- test("clamp", () {
- Int32 val = new Int32(17);
- expect(val.clamp(20, 30), new Int32(20));
- expect(val.clamp(10, 20), new Int32(17));
- expect(val.clamp(10, 15), new Int32(15));
-
- expect(val.clamp(new Int32(20), new Int32(30)), new Int32(20));
- expect(val.clamp(new Int32(10), new Int32(20)), new Int32(17));
- expect(val.clamp(new Int32(10), new Int32(15)), new Int32(15));
-
- expect(val.clamp(new Int64(20), new Int64(30)), new Int32(20));
- expect(val.clamp(new Int64(10), new Int64(20)), new Int32(17));
- expect(val.clamp(new Int64(10), new Int64(15)), new Int32(15));
- expect(val.clamp(Int64.MIN_VALUE, new Int64(30)), new Int32(17));
- expect(val.clamp(new Int64(10), Int64.MAX_VALUE), new Int32(17));
-
- expect(() => val.clamp(1, 'b'), throwsA(isArgumentError));
- expect(() => val.clamp('a', 1), throwsA(isArgumentError));
- });
- });
-
- group("comparison operators", () {
- test("<", () {
- expect(new Int32(17) < new Int32(18), true);
- expect(new Int32(17) < new Int32(17), false);
- expect(new Int32(17) < new Int32(16), false);
- expect(new Int32(17) < new Int64(18), true);
- expect(new Int32(17) < new Int64(17), false);
- expect(new Int32(17) < new Int64(16), false);
- expect(Int32.MIN_VALUE < Int32.MAX_VALUE, true);
- expect(Int32.MAX_VALUE < Int32.MIN_VALUE, false);
- expect(() => new Int32(17) < null, throws);
- });
-
- test("<=", () {
- expect(new Int32(17) <= new Int32(18), true);
- expect(new Int32(17) <= new Int32(17), true);
- expect(new Int32(17) <= new Int32(16), false);
- expect(new Int32(17) <= new Int64(18), true);
- expect(new Int32(17) <= new Int64(17), true);
- expect(new Int32(17) <= new Int64(16), false);
- expect(Int32.MIN_VALUE <= Int32.MAX_VALUE, true);
- expect(Int32.MAX_VALUE <= Int32.MIN_VALUE, false);
- expect(() => new Int32(17) <= null, throws);
- });
-
- test("==", () {
- expect(new Int32(17) == new Int32(18), false);
- expect(new Int32(17) == new Int32(17), true);
- expect(new Int32(17) == new Int32(16), false);
- expect(new Int32(17) == new Int64(18), false);
- expect(new Int32(17) == new Int64(17), true);
- expect(new Int32(17) == new Int64(16), false);
- expect(Int32.MIN_VALUE == Int32.MAX_VALUE, false);
- expect(new Int32(17) == new Object(), false);
- expect(new Int32(17) == null, false);
- });
-
- test(">=", () {
- expect(new Int32(17) >= new Int32(18), false);
- expect(new Int32(17) >= new Int32(17), true);
- expect(new Int32(17) >= new Int32(16), true);
- expect(new Int32(17) >= new Int64(18), false);
- expect(new Int32(17) >= new Int64(17), true);
- expect(new Int32(17) >= new Int64(16), true);
- expect(Int32.MIN_VALUE >= Int32.MAX_VALUE, false);
- expect(Int32.MAX_VALUE >= Int32.MIN_VALUE, true);
- expect(() => new Int32(17) >= null, throws);
- });
-
- test(">", () {
- expect(new Int32(17) > new Int32(18), false);
- expect(new Int32(17) > new Int32(17), false);
- expect(new Int32(17) > new Int32(16), true);
- expect(new Int32(17) > new Int64(18), false);
- expect(new Int32(17) > new Int64(17), false);
- expect(new Int32(17) > new Int64(16), true);
- expect(Int32.MIN_VALUE > Int32.MAX_VALUE, false);
- expect(Int32.MAX_VALUE > Int32.MIN_VALUE, true);
- expect(() => new Int32(17) > null, throws);
- });
- });
-
- group("bitwise operators", () {
- test("&", () {
- expect(new Int32(0x12345678) & new Int32(0x22222222),
- new Int32(0x12345678 & 0x22222222));
- expect(new Int32(0x12345678) & new Int64(0x22222222),
- new Int64(0x12345678 & 0x22222222));
- expect(() => new Int32(17) & null, throwsArgumentError);
- });
-
- test("|", () {
- expect(new Int32(0x12345678) | new Int32(0x22222222),
- new Int32(0x12345678 | 0x22222222));
- expect(new Int32(0x12345678) | new Int64(0x22222222),
- new Int64(0x12345678 | 0x22222222));
- expect(() => new Int32(17) | null, throws);
- });
-
- test("^", () {
- expect(new Int32(0x12345678) ^ new Int32(0x22222222),
- new Int32(0x12345678 ^ 0x22222222));
- expect(new Int32(0x12345678) ^ new Int64(0x22222222),
- new Int64(0x12345678 ^ 0x22222222));
- expect(() => new Int32(17) ^ null, throws);
- });
-
- test("~", () {
- expect(~(new Int32(0x12345678)), new Int32(~0x12345678));
- expect(-(new Int32(0x12345678)), new Int64(-0x12345678));
- });
- });
-
- group("bitshift operators", () {
- test("<<", () {
- expect(new Int32(0x12345678) << 7, new Int32(0x12345678 << 7));
- expect(() => new Int32(17) << -1, throwsArgumentError);
- expect(() => new Int32(17) << null, throws);
- });
-
- test(">>", () {
- expect(new Int32(0x12345678) >> 7, new Int32(0x12345678 >> 7));
- expect(() => new Int32(17) >> -1, throwsArgumentError);
- expect(() => new Int32(17) >> null, throws);
- });
-
- test("shiftRightUnsigned", () {
- expect(new Int32(0x12345678).shiftRightUnsigned(7),
- new Int32(0x12345678 >> 7));
- expect(() => (new Int32(17).shiftRightUnsigned(-1)), throwsArgumentError);
- expect(() => (new Int32(17).shiftRightUnsigned(null)), throws);
- });
- });
-
- group("conversions", () {
- test("toSigned", () {
- expect(Int32.ONE.toSigned(2), Int32.ONE);
- expect(Int32.ONE.toSigned(1), -Int32.ONE);
- expect(Int32.MAX_VALUE.toSigned(32), Int32.MAX_VALUE);
- expect(Int32.MIN_VALUE.toSigned(32), Int32.MIN_VALUE);
- expect(Int32.MAX_VALUE.toSigned(31), -Int32.ONE);
- expect(Int32.MIN_VALUE.toSigned(31), Int32.ZERO);
- expect(() => Int32.ONE.toSigned(0), throwsRangeError);
- expect(() => Int32.ONE.toSigned(33), throwsRangeError);
- });
- test("toUnsigned", () {
- expect(Int32.ONE.toUnsigned(1), Int32.ONE);
- expect(Int32.ONE.toUnsigned(0), Int32.ZERO);
- expect(Int32.MAX_VALUE.toUnsigned(32), Int32.MAX_VALUE);
- expect(Int32.MIN_VALUE.toUnsigned(32), Int32.MIN_VALUE);
- expect(Int32.MAX_VALUE.toUnsigned(31), Int32.MAX_VALUE);
- expect(Int32.MIN_VALUE.toUnsigned(31), Int32.ZERO);
- expect(() => Int32.ONE.toUnsigned(-1), throwsRangeError);
- expect(() => Int32.ONE.toUnsigned(33), throwsRangeError);
- });
- test("toDouble", () {
- expect(new Int32(17).toDouble(), same(17.0));
- expect(new Int32(-17).toDouble(), same(-17.0));
- });
- test("toInt", () {
- expect(new Int32(17).toInt(), 17);
- expect(new Int32(-17).toInt(), -17);
- });
- test("toInt32", () {
- expect(new Int32(17).toInt32(), new Int32(17));
- expect(new Int32(-17).toInt32(), new Int32(-17));
- });
- test("toInt64", () {
- expect(new Int32(17).toInt64(), new Int64(17));
- expect(new Int32(-17).toInt64(), new Int64(-17));
- });
- });
-
- group("parse", () {
- test("base 10", () {
- checkInt(int x) {
- expect(Int32.parseRadix('$x', 10), new Int32(x));
- }
- checkInt(0);
- checkInt(1);
- checkInt(1000);
- checkInt(12345678);
- checkInt(2147483647);
- checkInt(2147483648);
- checkInt(4294967295);
- checkInt(4294967296);
- expect(() => Int32.parseRadix('xyzzy', -1), throwsArgumentError);
- expect(() => Int32.parseRadix('plugh', 10),
- throwsA(new isInstanceOf<FormatException>()));
- });
-
- test("parseRadix", () {
- check(String s, int r, String x) {
- expect(Int32.parseRadix(s, r).toString(), x);
- }
- check('deadbeef', 16, '-559038737');
- check('95', 12, '113');
- });
- });
-
- group("string representation", () {
- test("toString", () {
- expect(new Int32(0).toString(), "0");
- expect(new Int32(1).toString(), "1");
- expect(new Int32(-1).toString(), "-1");
- expect(new Int32(1000).toString(), "1000");
- expect(new Int32(-1000).toString(), "-1000");
- expect(new Int32(123456789).toString(), "123456789");
- expect(new Int32(2147483647).toString(), "2147483647");
- expect(new Int32(2147483648).toString(), "-2147483648");
- expect(new Int32(2147483649).toString(), "-2147483647");
- expect(new Int32(2147483650).toString(), "-2147483646");
- expect(new Int32(-2147483648).toString(), "-2147483648");
- expect(new Int32(-2147483649).toString(), "2147483647");
- expect(new Int32(-2147483650).toString(), "2147483646");
- });
- });
-
- group("toHexString", () {
- test("returns hexadecimal string representation", () {
- expect(new Int32(-1).toHexString(), "-1");
- expect((new Int32(-1) >> 8).toHexString(), "-1");
- expect((new Int32(-1) << 8).toHexString(), "-100");
- expect(new Int32(123456789).toHexString(), "75bcd15");
- expect(new Int32(-1).shiftRightUnsigned(8).toHexString(), "ffffff");
- });
- });
-
- group("toRadixString", () {
- test("returns base n string representation", () {
- expect(new Int32(123456789).toRadixString(5), "223101104124");
- });
- });
-}
diff --git a/pkg/fixnum/test/int_64_test.dart b/pkg/fixnum/test/int_64_test.dart
deleted file mode 100644
index 1e17dae..0000000
--- a/pkg/fixnum/test/int_64_test.dart
+++ /dev/null
@@ -1,773 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library int64test;
-import 'package:fixnum/fixnum.dart';
-import 'package:unittest/unittest.dart';
-
-void main() {
-
- argumentErrorTest(name, op, [receiver = Int64.ONE]) {
- throwsArgumentErrorMentioning(substring) =>
- throwsA((e) => e is ArgumentError && '$e'.contains(substring));
-
- expect(() => op(receiver, null), throwsArgumentErrorMentioning('null'));
- expect(() => op(receiver, 'foo'), throwsArgumentErrorMentioning(r'"foo"'));
- }
-
- group("is-tests", () {
- test("isEven", () {
- expect((-Int64.ONE).isEven, false);
- expect(Int64.ZERO.isEven, true);
- expect(Int64.ONE.isEven, false);
- expect(Int64.TWO.isEven, true);
- });
- test("isMaxValue", () {
- expect(Int64.MIN_VALUE.isMaxValue, false);
- expect(Int64.ZERO.isMaxValue, false);
- expect(Int64.MAX_VALUE.isMaxValue, true);
- });
- test("isMinValue", () {
- expect(Int64.MIN_VALUE.isMinValue, true);
- expect(Int64.ZERO.isMinValue, false);
- expect(Int64.MAX_VALUE.isMinValue, false);
- });
- test("isNegative", () {
- expect(Int64.MIN_VALUE.isNegative, true);
- expect(Int64.ZERO.isNegative, false);
- expect(Int64.ONE.isNegative, false);
- });
- test("isOdd", () {
- expect((-Int64.ONE).isOdd, true);
- expect(Int64.ZERO.isOdd, false);
- expect(Int64.ONE.isOdd, true);
- expect(Int64.TWO.isOdd, false);
- });
- test("isZero", () {
- expect(Int64.MIN_VALUE.isZero, false);
- expect(Int64.ZERO.isZero, true);
- expect(Int64.MAX_VALUE.isZero, false);
- });
- test("bitLength", () {
- expect(new Int64(-2).bitLength, 1);
- expect((-Int64.ONE).bitLength, 0);
- expect(Int64.ZERO.bitLength, 0);
- expect((Int64.ONE << 21).bitLength, 22);
- expect((Int64.ONE << 22).bitLength, 23);
- expect((Int64.ONE << 43).bitLength, 44);
- expect((Int64.ONE << 44).bitLength, 45);
- expect(new Int64(2).bitLength, 2);
- expect(Int64.MAX_VALUE.bitLength, 63);
- expect(Int64.MIN_VALUE.bitLength, 63);
- });
- });
-
- group("arithmetic operators", () {
- Int64 n1 = new Int64(1234);
- Int64 n2 = new Int64(9876);
- Int64 n3 = new Int64(-1234);
- Int64 n4 = new Int64(-9876);
- Int64 n5 = new Int64.fromInts(0x12345678, 0xabcdabcd);
- Int64 n6 = new Int64.fromInts(0x77773333, 0x22224444);
-
- test("+", () {
- expect(n1 + n2, new Int64(11110));
- expect(n3 + n2, new Int64(8642));
- expect(n3 + n4, new Int64(-11110));
- expect(n5 + n6, new Int64.fromInts(0x89ab89ab, 0xcdeff011));
- expect(Int64.MAX_VALUE + 1, Int64.MIN_VALUE);
- argumentErrorTest("+", (a, b) => a + b);
- });
-
- test("-", () {
- expect(n1 - n2, new Int64(-8642));
- expect(n3 - n2, new Int64(-11110));
- expect(n3 - n4, new Int64(8642));
- expect(n5 - n6, new Int64.fromInts(0x9abd2345, 0x89ab6789));
- expect(Int64.MIN_VALUE - 1, Int64.MAX_VALUE);
- argumentErrorTest("-", (a, b) => a - b);
- });
-
- test("unary -", () {
- expect(-n1, new Int64(-1234));
- expect(-Int64.ZERO, Int64.ZERO);
- });
-
- test("*", () {
- expect(new Int64(1111) * new Int64(3), new Int64(3333));
- expect(new Int64(1111) * new Int64(-3), new Int64(-3333));
- expect(new Int64(-1111) * new Int64(3), new Int64(-3333));
- expect(new Int64(-1111) * new Int64(-3), new Int64(3333));
- expect(new Int64(100) * Int64.ZERO, Int64.ZERO);
-
- expect(new Int64.fromInts(0x12345678, 0x12345678) *
- new Int64.fromInts(0x1234, 0x12345678),
- new Int64.fromInts(0x7ff63f7c, 0x1df4d840));
- expect(new Int64.fromInts(0xf2345678, 0x12345678) *
- new Int64.fromInts(0x1234, 0x12345678),
- new Int64.fromInts(0x7ff63f7c, 0x1df4d840));
- expect(new Int64.fromInts(0xf2345678, 0x12345678) *
- new Int64.fromInts(0xffff1234, 0x12345678),
- new Int64.fromInts(0x297e3f7c, 0x1df4d840));
-
- // RHS Int32
- expect((new Int64(123456789) * new Int32(987654321)),
- new Int64.fromInts(0x1b13114, 0xfbff5385));
- expect((new Int64(123456789) * new Int32(987654321)),
- new Int64.fromInts(0x1b13114, 0xfbff5385));
-
- // Wraparound
- expect((new Int64(123456789) * new Int64(987654321)),
- new Int64.fromInts(0x1b13114, 0xfbff5385));
-
- expect(Int64.MIN_VALUE * new Int64(2), Int64.ZERO);
- expect(Int64.MIN_VALUE * new Int64(1), Int64.MIN_VALUE);
- expect(Int64.MIN_VALUE * new Int64(-1), Int64.MIN_VALUE);
- argumentErrorTest("*", (a, b) => a * b);
- });
-
- test("~/", () {
- Int64 deadBeef = new Int64.fromInts(0xDEADBEEF, 0xDEADBEEF);
- Int64 ten = new Int64(10);
-
- expect(deadBeef ~/ ten, new Int64.fromInts(0xfcaaf97e, 0x63115fe5));
- expect(Int64.ONE ~/ Int64.TWO, Int64.ZERO);
- expect(Int64.MAX_VALUE ~/ Int64.TWO,
- new Int64.fromInts(0x3fffffff, 0xffffffff));
- expect(Int64.ZERO ~/ new Int64(1000), Int64.ZERO);
- expect(Int64.MIN_VALUE ~/ Int64.MIN_VALUE, Int64.ONE);
- expect(new Int64(1000) ~/ Int64.MIN_VALUE, Int64.ZERO);
- expect(Int64.MIN_VALUE ~/ new Int64(8192), new Int64(-1125899906842624));
- expect(Int64.MIN_VALUE ~/ new Int64(8193), new Int64(-1125762484664320));
- expect(new Int64(-1000) ~/ new Int64(8192), Int64.ZERO);
- expect(new Int64(-1000) ~/ new Int64(8193), Int64.ZERO);
- expect(new Int64(-1000000000) ~/ new Int64(8192), new Int64(-122070));
- expect(new Int64(-1000000000) ~/ new Int64(8193), new Int64(-122055));
- expect(new Int64(1000000000) ~/ new Int64(8192), new Int64(122070));
- expect(new Int64(1000000000) ~/ new Int64(8193), new Int64(122055));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x00000400),
- new Int64.fromInts(0x1fffff, 0xffffffff));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x00040000),
- new Int64.fromInts(0x1fff, 0xffffffff));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x04000000),
- new Int64.fromInts(0x1f, 0xffffffff));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000004, 0x00000000),
- new Int64(536870911));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000400, 0x00000000),
- new Int64(2097151));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00040000, 0x00000000),
- new Int64(8191));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x04000000, 0x00000000),
- new Int64(31));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x00000300),
- new Int64.fromInts(0x2AAAAA, 0xAAAAAAAA));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x30000000),
- new Int64.fromInts(0x2, 0xAAAAAAAA));
- expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00300000, 0x00000000),
- new Int64(0x2AA));
- expect(Int64.MAX_VALUE ~/ new Int64(0x123456),
- new Int64.fromInts(0x708, 0x002E9501));
- expect(Int64.MAX_VALUE % new Int64(0x123456), new Int64(0x3BDA9));
- expect(new Int64(5) ~/ new Int64(5), Int64.ONE);
- expect(new Int64(1000) ~/ new Int64(3), new Int64(333));
- expect(new Int64(1000) ~/ new Int64(-3), new Int64(-333));
- expect(new Int64(-1000) ~/ new Int64(3), new Int64(-333));
- expect(new Int64(-1000) ~/ new Int64(-3), new Int64(333));
- expect(new Int64(3) ~/ new Int64(1000), Int64.ZERO);
- expect(new Int64.fromInts( 0x12345678, 0x12345678) ~/
- new Int64.fromInts(0x0, 0x123),
- new Int64.fromInts(0x1003d0, 0xe84f5ae8));
- expect(new Int64.fromInts(0x12345678, 0x12345678) ~/
- new Int64.fromInts(0x1234, 0x12345678),
- new Int64.fromInts(0x0, 0x10003));
- expect(new Int64.fromInts(0xf2345678, 0x12345678) ~/
- new Int64.fromInts(0x1234, 0x12345678),
- new Int64.fromInts(0xffffffff, 0xffff3dfe));
- expect(new Int64.fromInts(0xf2345678, 0x12345678) ~/
- new Int64.fromInts(0xffff1234, 0x12345678),
- new Int64.fromInts(0x0, 0xeda));
- expect(new Int64(829893893) ~/ new Int32(1919), new Int32(432461));
- expect(new Int64(829893893) ~/ new Int64(1919), new Int32(432461));
- expect(new Int64(829893893) ~/ 1919, new Int32(432461));
- expect(() => new Int64(1) ~/ Int64.ZERO,
- throwsA(new isInstanceOf<IntegerDivisionByZeroException>()));
- expect(Int64.MIN_VALUE ~/ new Int64(2),
- new Int64.fromInts(0xc0000000, 0x00000000));
- expect(Int64.MIN_VALUE ~/ new Int64(1), Int64.MIN_VALUE);
- expect(Int64.MIN_VALUE ~/ new Int64(-1), Int64.MIN_VALUE);
- expect(() => new Int64(17) ~/ Int64.ZERO, throws);
- argumentErrorTest("~/", (a, b) => a ~/ b);
- });
-
- test("%", () {
- // Define % as Euclidean mod, with positive result for all arguments
- expect(Int64.ZERO % new Int64(1000), Int64.ZERO);
- expect(Int64.MIN_VALUE % Int64.MIN_VALUE, Int64.ZERO);
- expect(new Int64(1000) % Int64.MIN_VALUE, new Int64(1000));
- expect(Int64.MIN_VALUE % new Int64(8192), Int64.ZERO);
- expect(Int64.MIN_VALUE % new Int64(8193), new Int64(6145));
- expect(new Int64(-1000) % new Int64(8192), new Int64(7192));
- expect(new Int64(-1000) % new Int64(8193), new Int64(7193));
- expect(new Int64(-1000000000) % new Int64(8192), new Int64(5632));
- expect(new Int64(-1000000000) % new Int64(8193), new Int64(4808));
- expect(new Int64(1000000000) % new Int64(8192), new Int64(2560));
- expect(new Int64(1000000000) % new Int64(8193), new Int64(3385));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000000, 0x00000400),
- new Int64.fromInts(0x0, 0x3ff));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000000, 0x00040000),
- new Int64.fromInts(0x0, 0x3ffff));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000000, 0x04000000),
- new Int64.fromInts(0x0, 0x3ffffff));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000004, 0x00000000),
- new Int64.fromInts(0x3, 0xffffffff));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000400, 0x00000000),
- new Int64.fromInts(0x3ff, 0xffffffff));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x00040000, 0x00000000),
- new Int64.fromInts(0x3ffff, 0xffffffff));
- expect(Int64.MAX_VALUE % new Int64.fromInts(0x04000000, 0x00000000),
- new Int64.fromInts(0x3ffffff, 0xffffffff));
- expect(new Int64(0x12345678).remainder(new Int64(0x22)),
- new Int64(0x12345678.remainder(0x22)));
- expect(new Int64(0x12345678).remainder(new Int64(-0x22)),
- new Int64(0x12345678.remainder(-0x22)));
- expect(new Int64(-0x12345678).remainder(new Int64(-0x22)),
- new Int64(-0x12345678.remainder(-0x22)));
- expect(new Int64(-0x12345678).remainder(new Int64(0x22)),
- new Int64(-0x12345678.remainder(0x22)));
- expect(new Int32(0x12345678).remainder(new Int64(0x22)),
- new Int64(0x12345678.remainder(0x22)));
- argumentErrorTest("%", (a, b) => a % b);
- });
-
- test("clamp", () {
- Int64 val = new Int64(17);
- expect(val.clamp(20, 30), new Int64(20));
- expect(val.clamp(10, 20), new Int64(17));
- expect(val.clamp(10, 15), new Int64(15));
-
- expect(val.clamp(new Int32(20), new Int32(30)), new Int64(20));
- expect(val.clamp(new Int32(10), new Int32(20)), new Int64(17));
- expect(val.clamp(new Int32(10), new Int32(15)), new Int64(15));
-
- expect(val.clamp(new Int64(20), new Int64(30)), new Int64(20));
- expect(val.clamp(new Int64(10), new Int64(20)), new Int64(17));
- expect(val.clamp(new Int64(10), new Int64(15)), new Int64(15));
- expect(val.clamp(Int64.MIN_VALUE, new Int64(30)), new Int64(17));
- expect(val.clamp(new Int64(10), Int64.MAX_VALUE), new Int64(17));
-
- expect(() => val.clamp(1, 'b'), throwsA(isArgumentError));
- expect(() => val.clamp('a', 1), throwsA(isArgumentError));
- });
- });
-
- group("comparison operators", () {
- Int64 largeNeg = new Int64.fromInts(0x82341234, 0x0);
- Int64 largePos = new Int64.fromInts(0x12341234, 0x0);
- Int64 largePosPlusOne = largePos + new Int64(1);
-
- test("<", () {
- expect(new Int64(10) < new Int64(11), true);
- expect(new Int64(10) < new Int64(10), false);
- expect(new Int64(10) < new Int64(9), false);
- expect(new Int64(10) < new Int32(11), true);
- expect(new Int64(10) < new Int32(10), false);
- expect(new Int64(10) < new Int32(9), false);
- expect(new Int64(-10) < new Int64(-11), false);
- expect(Int64.MIN_VALUE < Int64.ZERO, true);
- expect(largeNeg < largePos, true);
- expect(largePos < largePosPlusOne, true);
- expect(largePos < largePos, false);
- expect(largePosPlusOne < largePos, false);
- expect(Int64.MIN_VALUE < Int64.MAX_VALUE, true);
- expect(Int64.MAX_VALUE < Int64.MIN_VALUE, false);
- argumentErrorTest("<", (a, b) => a < b);
- });
-
- test("<=", () {
- expect(new Int64(10) <= new Int64(11), true);
- expect(new Int64(10) <= new Int64(10), true);
- expect(new Int64(10) <= new Int64(9), false);
- expect(new Int64(10) <= new Int32(11), true);
- expect(new Int64(10) <= new Int32(10), true);
- expect(new Int64(10) <= new Int64(9), false);
- expect(new Int64(-10) <= new Int64(-11), false);
- expect(new Int64(-10) <= new Int64(-10), true);
- expect(largeNeg <= largePos, true);
- expect(largePos <= largeNeg, false);
- expect(largePos <= largePosPlusOne, true);
- expect(largePos <= largePos, true);
- expect(largePosPlusOne <= largePos, false);
- expect(Int64.MIN_VALUE <= Int64.MAX_VALUE, true);
- expect(Int64.MAX_VALUE <= Int64.MIN_VALUE, false);
- argumentErrorTest("<=", (a, b) => a <= b);
- });
-
- test("==", () {
- expect(new Int64(10) == new Int64(11), false);
- expect(new Int64(10) == new Int64(10), true);
- expect(new Int64(10) == new Int64(9), false);
- expect(new Int64(10) == new Int32(11), false);
- expect(new Int64(10) == new Int32(10), true);
- expect(new Int64(10) == new Int32(9), false);
- expect(new Int64(-10) == new Int64(-10), true);
- expect(new Int64(-10) != new Int64(-10), false);
- expect(largePos == largePos, true);
- expect(largePos == largePosPlusOne, false);
- expect(largePosPlusOne == largePos, false);
- expect(Int64.MIN_VALUE == Int64.MAX_VALUE, false);
- expect(new Int64(17) == new Object(), false);
- expect(new Int64(17) == null, false);
- });
-
- test(">=", () {
- expect(new Int64(10) >= new Int64(11), false);
- expect(new Int64(10) >= new Int64(10), true);
- expect(new Int64(10) >= new Int64(9), true);
- expect(new Int64(10) >= new Int32(11), false);
- expect(new Int64(10) >= new Int32(10), true);
- expect(new Int64(10) >= new Int32(9), true);
- expect(new Int64(-10) >= new Int64(-11), true);
- expect(new Int64(-10) >= new Int64(-10), true);
- expect(largePos >= largeNeg, true);
- expect(largeNeg >= largePos, false);
- expect(largePos >= largePosPlusOne, false);
- expect(largePos >= largePos, true);
- expect(largePosPlusOne >= largePos, true);
- expect(Int64.MIN_VALUE >= Int64.MAX_VALUE, false);
- expect(Int64.MAX_VALUE >= Int64.MIN_VALUE, true);
- argumentErrorTest(">=", (a, b) => a >= b);
- });
-
- test(">", () {
- expect(new Int64(10) > new Int64(11), false);
- expect(new Int64(10) > new Int64(10), false);
- expect(new Int64(10) > new Int64(9), true);
- expect(new Int64(10) > new Int32(11), false);
- expect(new Int64(10) > new Int32(10), false);
- expect(new Int64(10) > new Int32(9), true);
- expect(new Int64(-10) > new Int64(-11), true);
- expect(new Int64(10) > new Int64(-11), true);
- expect(new Int64(-10) > new Int64(11), false);
- expect(largePos > largeNeg, true);
- expect(largeNeg > largePos, false);
- expect(largePos > largePosPlusOne, false);
- expect(largePos > largePos, false);
- expect(largePosPlusOne > largePos, true);
- expect(Int64.ZERO > Int64.MIN_VALUE, true);
- expect(Int64.MIN_VALUE > Int64.MAX_VALUE, false);
- expect(Int64.MAX_VALUE > Int64.MIN_VALUE, true);
- argumentErrorTest(">", (a, b) => a > b);
- });
- });
-
- group("bitwise operators", () {
- Int64 n1 = new Int64(1234);
- Int64 n2 = new Int64(9876);
- Int64 n3 = new Int64(-1234);
- Int64 n4 = new Int64(0x1234) << 32;
- Int64 n5 = new Int64(0x9876) << 32;
-
- test("&", () {
- expect(n1 & n2, new Int64(1168));
- expect(n3 & n2, new Int64(8708));
- expect(n4 & n5, new Int64(0x1034) << 32);
- expect(() => n1 & null, throwsArgumentError);
- argumentErrorTest("&", (a, b) => a & b);
- });
-
- test("|", () {
- expect(n1 | n2, new Int64(9942));
- expect(n3 | n2, new Int64(-66));
- expect(n4 | n5, new Int64(0x9a76) << 32);
- expect(() => n1 | null, throwsArgumentError);
- argumentErrorTest("|", (a, b) => a | b);
- });
-
- test("^", () {
- expect(n1 ^ n2, new Int64(8774));
- expect(n3 ^ n2, new Int64(-8774));
- expect(n4 ^ n5, new Int64(0x8a42) << 32);
- expect(() => n1 ^ null, throwsArgumentError);
- argumentErrorTest("^", (a, b) => a ^ b);
- });
-
- test("~", () {
- expect(-new Int64(1), new Int64(-1));
- expect(-new Int64(-1), new Int64(1));
- expect(-Int64.MIN_VALUE, Int64.MIN_VALUE);
-
- expect(~n1, new Int64(-1235));
- expect(~n2, new Int64(-9877));
- expect(~n3, new Int64(1233));
- expect(~n4, new Int64.fromInts(0xffffedcb, 0xffffffff));
- expect(~n5, new Int64.fromInts(0xffff6789, 0xffffffff));
- });
- });
-
- group("bitshift operators", () {
- test("<<", () {
- expect(new Int64.fromInts(0x12341234, 0x45674567) << 10,
- new Int64.fromInts(0xd048d115, 0x9d159c00));
- expect(new Int64.fromInts(0x92341234, 0x45674567) << 10,
- new Int64.fromInts(0xd048d115, 0x9d159c00));
- expect(new Int64(-1) << 5, new Int64(-32));
- expect(new Int64(-1) << 0, new Int64(-1));
- expect(() => new Int64(17) << -1, throwsArgumentError);
- expect(() => new Int64(17) << null, throws);
- });
-
- test(">>", () {
- expect((Int64.MIN_VALUE >> 13).toString(), "-1125899906842624");
- expect(new Int64.fromInts(0x12341234, 0x45674567) >> 10,
- new Int64.fromInts(0x48d04, 0x8d1159d1));
- expect(new Int64.fromInts(0x92341234, 0x45674567) >> 10,
- new Int64.fromInts(0xffe48d04, 0x8d1159d1));
- expect(new Int64.fromInts(0xFFFFFFF, 0xFFFFFFFF) >> 34,
- new Int64(67108863));
- for (int n = 0; n <= 66; n++) {
- expect(new Int64(-1) >> n, new Int64(-1));
- }
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 8,
- new Int64.fromInts(0x00723456, 0x789abcde));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 16,
- new Int64.fromInts(0x00007234, 0x56789abc));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 24,
- new Int64.fromInts(0x00000072, 0x3456789a));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 28,
- new Int64.fromInts(0x00000007, 0x23456789));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 32,
- new Int64.fromInts(0x00000000, 0x72345678));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 36,
- new Int64.fromInts(0x00000000, 0x07234567));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 40,
- new Int64.fromInts(0x00000000, 0x00723456));
- expect(new Int64.fromInts(0x72345678, 0x9abcde00) >> 44,
- new Int64.fromInts(0x00000000, 0x00072345));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 48,
- new Int64.fromInts(0x00000000, 0x00007234));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 8,
- new Int64.fromInts(0xff923456, 0x789abcde));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 16,
- new Int64.fromInts(0xffff9234, 0x56789abc));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 24,
- new Int64.fromInts(0xffffff92, 0x3456789a));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 28,
- new Int64.fromInts(0xfffffff9, 0x23456789));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 32,
- new Int64.fromInts(0xffffffff, 0x92345678));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 36,
- new Int64.fromInts(0xffffffff, 0xf9234567));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 40,
- new Int64.fromInts(0xffffffff, 0xff923456));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 44,
- new Int64.fromInts(0xffffffff, 0xfff92345));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 48,
- new Int64.fromInts(0xffffffff, 0xffff9234));
- expect(() => new Int64(17) >> -1, throwsArgumentError);
- expect(() => new Int64(17) >> null, throws);
- });
-
- test("shiftRightUnsigned", () {
- expect(new Int64.fromInts(0x12341234, 0x45674567).shiftRightUnsigned(10),
- new Int64.fromInts(0x48d04, 0x8d1159d1));
- expect(new Int64.fromInts(0x92341234, 0x45674567).shiftRightUnsigned(10),
- new Int64.fromInts(0x248d04, 0x8d1159d1));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(8),
- new Int64.fromInts(0x00723456, 0x789abcde));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(16),
- new Int64.fromInts(0x00007234, 0x56789abc));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(24),
- new Int64.fromInts(0x00000072, 0x3456789a));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(28),
- new Int64.fromInts(0x00000007, 0x23456789));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(32),
- new Int64.fromInts(0x00000000, 0x72345678));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(36),
- new Int64.fromInts(0x00000000, 0x07234567));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(40),
- new Int64.fromInts(0x00000000, 0x00723456));
- expect(new Int64.fromInts(0x72345678, 0x9abcde00).shiftRightUnsigned(44),
- new Int64.fromInts(0x00000000, 0x00072345));
- expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(48),
- new Int64.fromInts(0x00000000, 0x00007234));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(8),
- new Int64.fromInts(0x00923456, 0x789abcde));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(16),
- new Int64.fromInts(0x00009234, 0x56789abc));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(24),
- new Int64.fromInts(0x00000092, 0x3456789a));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(28),
- new Int64.fromInts(0x00000009, 0x23456789));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(32),
- new Int64.fromInts(0x00000000, 0x92345678));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(36),
- new Int64.fromInts(0x00000000, 0x09234567));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(40),
- new Int64.fromInts(0x00000000, 0x00923456));
- expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(44),
- new Int64.fromInts(0x00000000, 0x00092345));
- expect(new Int64.fromInts(0x00000000, 0x00009234),
- new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(48));
- expect(() => new Int64(17).shiftRightUnsigned(-1),
- throwsArgumentError);
- expect(() => new Int64(17).shiftRightUnsigned(null), throws);
- });
-
- test("overflow", () {
- expect((new Int64(1) << 63) >> 1,
- -new Int64.fromInts(0x40000000, 0x00000000));
- expect((new Int64(-1) << 32) << 32, new Int64(0));
- expect(Int64.MIN_VALUE << 0, Int64.MIN_VALUE);
- expect(Int64.MIN_VALUE << 1, new Int64(0));
- expect((-new Int64.fromInts(8, 0)) >> 1,
- new Int64.fromInts(0xfffffffc, 0x00000000));
- expect((-new Int64.fromInts(8, 0)).shiftRightUnsigned(1),
- new Int64.fromInts(0x7ffffffc, 0x0));
- });
- });
-
- group("conversions", () {
- test("toSigned", () {
- expect((Int64.ONE << 44).toSigned(46), Int64.ONE << 44);
- expect((Int64.ONE << 44).toSigned(45), -(Int64.ONE << 44));
- expect((Int64.ONE << 22).toSigned(24), Int64.ONE << 22);
- expect((Int64.ONE << 22).toSigned(23), -(Int64.ONE << 22));
- expect(Int64.ONE.toSigned(2), Int64.ONE);
- expect(Int64.ONE.toSigned(1), -Int64.ONE);
- expect(Int64.MAX_VALUE.toSigned(64), Int64.MAX_VALUE);
- expect(Int64.MIN_VALUE.toSigned(64), Int64.MIN_VALUE);
- expect(Int64.MAX_VALUE.toSigned(63), -Int64.ONE);
- expect(Int64.MIN_VALUE.toSigned(63), Int64.ZERO);
- expect(() => Int64.ONE.toSigned(0), throwsRangeError);
- expect(() => Int64.ONE.toSigned(65), throwsRangeError);
- });
- test("toUnsigned", () {
- expect((Int64.ONE << 44).toUnsigned(45), Int64.ONE << 44);
- expect((Int64.ONE << 44).toUnsigned(44), Int64.ZERO);
- expect((Int64.ONE << 22).toUnsigned(23), Int64.ONE << 22);
- expect((Int64.ONE << 22).toUnsigned(22), Int64.ZERO);
- expect(Int64.ONE.toUnsigned(1), Int64.ONE);
- expect(Int64.ONE.toUnsigned(0), Int64.ZERO);
- expect(Int64.MAX_VALUE.toUnsigned(64), Int64.MAX_VALUE);
- expect(Int64.MIN_VALUE.toUnsigned(64), Int64.MIN_VALUE);
- expect(Int64.MAX_VALUE.toUnsigned(63), Int64.MAX_VALUE);
- expect(Int64.MIN_VALUE.toUnsigned(63), Int64.ZERO);
- expect(() => Int64.ONE.toUnsigned(-1), throwsRangeError);
- expect(() => Int64.ONE.toUnsigned(65), throwsRangeError);
- });
- test("toDouble", () {
- expect(new Int64(0).toDouble(), same(0.0));
- expect(new Int64(100).toDouble(), same(100.0));
- expect(new Int64(-100).toDouble(), same(-100.0));
- expect(new Int64(2147483647).toDouble(), same(2147483647.0));
- expect(new Int64(2147483648).toDouble(), same(2147483648.0));
- expect(new Int64(-2147483647).toDouble(), same(-2147483647.0));
- expect(new Int64(-2147483648).toDouble(), same(-2147483648.0));
- expect(new Int64(4503599627370495).toDouble(), same(4503599627370495.0));
- expect(new Int64(4503599627370496).toDouble(), same(4503599627370496.0));
- expect(new Int64(-4503599627370495).toDouble(),
- same(-4503599627370495.0));
- expect(new Int64(-4503599627370496).toDouble(),
- same(-4503599627370496.0));
- expect(Int64.parseInt("-10000000000000000").toDouble().toStringAsFixed(1),
- "-10000000000000000.0");
- expect(Int64.parseInt("-10000000000000001").toDouble().toStringAsFixed(1),
- "-10000000000000000.0");
- expect(Int64.parseInt("-10000000000000002").toDouble().toStringAsFixed(1),
- "-10000000000000002.0");
- expect(Int64.parseInt("-10000000000000003").toDouble().toStringAsFixed(1),
- "-10000000000000004.0");
- expect(Int64.parseInt("-10000000000000004").toDouble().toStringAsFixed(1),
- "-10000000000000004.0");
- expect(Int64.parseInt("-10000000000000005").toDouble().toStringAsFixed(1),
- "-10000000000000004.0");
- expect(Int64.parseInt("-10000000000000006").toDouble().toStringAsFixed(1),
- "-10000000000000006.0");
- expect(Int64.parseInt("-10000000000000007").toDouble().toStringAsFixed(1),
- "-10000000000000008.0");
- expect(Int64.parseInt("-10000000000000008").toDouble().toStringAsFixed(1),
- "-10000000000000008.0");
- });
-
- test("toInt", () {
- expect(new Int64(0).toInt(), 0);
- expect(new Int64(100).toInt(), 100);
- expect(new Int64(-100).toInt(), -100);
- expect(new Int64(2147483647).toInt(), 2147483647);
- expect(new Int64(2147483648).toInt(), 2147483648);
- expect(new Int64(-2147483647).toInt(), -2147483647);
- expect(new Int64(-2147483648).toInt(), -2147483648);
- expect(new Int64(4503599627370495).toInt(), 4503599627370495);
- expect(new Int64(4503599627370496).toInt(), 4503599627370496);
- expect(new Int64(-4503599627370495).toInt(), -4503599627370495);
- expect(new Int64(-4503599627370496).toInt(), -4503599627370496);
- expect(Int64.parseInt("-10000000000000000").toInt(),
- same(-10000000000000000));
- expect(Int64.parseInt("-10000000000000001").toInt(),
- same(-10000000000000001));
- expect(Int64.parseInt("-10000000000000002").toInt(),
- same(-10000000000000002));
- expect(Int64.parseInt("-10000000000000003").toInt(),
- same(-10000000000000003));
- expect(Int64.parseInt("-10000000000000004").toInt(),
- same(-10000000000000004));
- expect(Int64.parseInt("-10000000000000005").toInt(),
- same(-10000000000000005));
- expect(Int64.parseInt("-10000000000000006").toInt(),
- same(-10000000000000006));
- expect(Int64.parseInt("-10000000000000007").toInt(),
- same(-10000000000000007));
- expect(Int64.parseInt("-10000000000000008").toInt(),
- same(-10000000000000008));
- });
-
- test("toInt32", () {
- expect(new Int64(0).toInt32(), new Int32(0));
- expect(new Int64(1).toInt32(), new Int32(1));
- expect(new Int64(-1).toInt32(), new Int32(-1));
- expect(new Int64(2147483647).toInt32(), new Int32(2147483647));
- expect(new Int64(2147483648).toInt32(), new Int32(-2147483648));
- expect(new Int64(2147483649).toInt32(), new Int32(-2147483647));
- expect(new Int64(2147483650).toInt32(), new Int32(-2147483646));
- expect(new Int64(-2147483648).toInt32(), new Int32(-2147483648));
- expect(new Int64(-2147483649).toInt32(), new Int32(2147483647));
- expect(new Int64(-2147483650).toInt32(), new Int32(2147483646));
- expect(new Int64(-2147483651).toInt32(), new Int32(2147483645));
- });
- });
-
- test("JavaScript 53-bit integer boundary", () {
- Int64 _factorial(Int64 n) {
- if (n.isZero) {
- return new Int64(1);
- } else {
- return n * _factorial(n - new Int64(1));
- }
- }
- Int64 fact18 = _factorial(new Int64(18));
- Int64 fact17 = _factorial(new Int64(17));
- expect(fact18 ~/ fact17, new Int64(18));
- });
-
- test("min, max values", () {
- expect(new Int64(1) << 63, Int64.MIN_VALUE);
- expect(-(Int64.MIN_VALUE + new Int64(1)), Int64.MAX_VALUE);
- });
-
- group("parse", () {
- test("parseRadix10", () {
- checkInt(int x) {
- expect(Int64.parseRadix('$x', 10), new Int64(x));
- }
- checkInt(0);
- checkInt(1);
- checkInt(-1);
- checkInt(1000);
- checkInt(12345678);
- checkInt(-12345678);
- checkInt(2147483647);
- checkInt(2147483648);
- checkInt(-2147483647);
- checkInt(-2147483648);
- checkInt(4294967295);
- checkInt(4294967296);
- checkInt(-4294967295);
- checkInt(-4294967296);
- });
-
- test("parseRadix", () {
- check(String s, int r, String x) {
- expect(Int64.parseRadix(s, r).toString(), x);
- }
- check('ghoul', 36, '27699213');
- check('ghoul', 35, '24769346');
- // Min and max value.
- check("-9223372036854775808", 10, "-9223372036854775808");
- check("9223372036854775807", 10, "9223372036854775807");
- // Overflow during parsing.
- check("9223372036854775808", 10, "-9223372036854775808");
-
- expect(() => Int64.parseRadix('0', 1), throwsRangeError);
- expect(() => Int64.parseRadix('0', 37), throwsRangeError);
- expect(() => Int64.parseRadix('xyzzy', -1), throwsRangeError);
- expect(() => Int64.parseRadix('xyzzy', 10), throwsFormatException);
- });
-
- test("parseRadixN", () {
- check(String s, int r) {
- expect(Int64.parseRadix(s, r).toRadixString(r), s);
- }
- check("2ppp111222333", 33); // This value & radix requires three chunks.
- });
- });
-
- group("string representation", () {
- test("toString", () {
- expect(new Int64(0).toString(), "0");
- expect(new Int64(1).toString(), "1");
- expect(new Int64(-1).toString(), "-1");
- expect(new Int64(-10).toString(), "-10");
- expect(Int64.MIN_VALUE.toString(), "-9223372036854775808");
- expect(Int64.MAX_VALUE.toString(), "9223372036854775807");
-
- int top = 922337201;
- int bottom = 967490662;
- Int64 fullnum = (new Int64(1000000000) * new Int64(top)) +
- new Int64(bottom);
- expect(fullnum.toString(), "922337201967490662");
- expect((-fullnum).toString(), "-922337201967490662");
- expect(new Int64(123456789).toString(), "123456789");
- });
-
- test("toHexString", () {
- Int64 deadbeef12341234 = new Int64.fromInts(0xDEADBEEF, 0x12341234);
- expect(Int64.ZERO.toHexString(), "0");
- expect(deadbeef12341234.toHexString(), "DEADBEEF12341234");
- expect(new Int64.fromInts(0x17678A7, 0xDEF01234).toHexString(),
- "17678A7DEF01234");
- expect(new Int64(123456789).toHexString(), "75BCD15");
- });
-
- test("toRadixString", () {
- expect(new Int64(123456789).toRadixString(5), "223101104124");
- expect(Int64.MIN_VALUE.toRadixString(2),
- "-1000000000000000000000000000000000000000000000000000000000000000");
- expect(Int64.MIN_VALUE.toRadixString(3),
- "-2021110011022210012102010021220101220222");
- expect(Int64.MIN_VALUE.toRadixString(4),
- "-20000000000000000000000000000000");
- expect(Int64.MIN_VALUE.toRadixString(5), "-1104332401304422434310311213");
- expect(Int64.MIN_VALUE.toRadixString(6), "-1540241003031030222122212");
- expect(Int64.MIN_VALUE.toRadixString(7), "-22341010611245052052301");
- expect(Int64.MIN_VALUE.toRadixString(8), "-1000000000000000000000");
- expect(Int64.MIN_VALUE.toRadixString(9), "-67404283172107811828");
- expect(Int64.MIN_VALUE.toRadixString(10), "-9223372036854775808");
- expect(Int64.MIN_VALUE.toRadixString(11), "-1728002635214590698");
- expect(Int64.MIN_VALUE.toRadixString(12), "-41a792678515120368");
- expect(Int64.MIN_VALUE.toRadixString(13), "-10b269549075433c38");
- expect(Int64.MIN_VALUE.toRadixString(14), "-4340724c6c71dc7a8");
- expect(Int64.MIN_VALUE.toRadixString(15), "-160e2ad3246366808");
- expect(Int64.MIN_VALUE.toRadixString(16), "-8000000000000000");
- expect(Int64.MAX_VALUE.toRadixString(2),
- "111111111111111111111111111111111111111111111111111111111111111");
- expect(Int64.MAX_VALUE.toRadixString(3),
- "2021110011022210012102010021220101220221");
- expect(Int64.MAX_VALUE.toRadixString(4),
- "13333333333333333333333333333333");
- expect(Int64.MAX_VALUE.toRadixString(5), "1104332401304422434310311212");
- expect(Int64.MAX_VALUE.toRadixString(6), "1540241003031030222122211");
- expect(Int64.MAX_VALUE.toRadixString(7), "22341010611245052052300");
- expect(Int64.MAX_VALUE.toRadixString(8), "777777777777777777777");
- expect(Int64.MAX_VALUE.toRadixString(9), "67404283172107811827");
- expect(Int64.MAX_VALUE.toRadixString(10), "9223372036854775807");
- expect(Int64.MAX_VALUE.toRadixString(11), "1728002635214590697");
- expect(Int64.MAX_VALUE.toRadixString(12), "41a792678515120367");
- expect(Int64.MAX_VALUE.toRadixString(13), "10b269549075433c37");
- expect(Int64.MAX_VALUE.toRadixString(14), "4340724c6c71dc7a7");
- expect(Int64.MAX_VALUE.toRadixString(15), "160e2ad3246366807");
- expect(() => Int64.ZERO.toRadixString(1), throwsRangeError);
- expect(() => Int64.ZERO.toRadixString(37), throwsRangeError);
- });
- });
-}
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index b7c6b01..474ddfe 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.12.1
+* Fixed markdown in dartdocs.
+
## 0.12.0
* Introduce `@optionalTypeArgs` annotation for classes whose type arguments are to be treated as optional.
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index b8142fd..ff0f9b0 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -24,6 +24,7 @@
/// same annotation.
///
/// Tools, such as the analyzer, can provide feedback if
+///
/// * the annotation is associated with anything other than an instance method,
/// or
/// * a method that has this annotation that can return anything other than a
@@ -35,6 +36,7 @@
/// arguments to the constructor is not a compile-time constant.
///
/// Tools, such as the analyzer, can provide feedback if
+///
/// * the annotation is associated with anything other than a const constructor,
/// or
/// * an invocation of a constructor that has this annotation is not invoked
@@ -50,6 +52,7 @@
/// outside of the library that defines the annotated method.
///
/// Tools, such as the analyzer, can provide feedback if
+///
/// * the annotation is associated with anything other than an instance method,
/// or
/// * a method that overrides a method that has this annotation can return
@@ -70,6 +73,7 @@
/// that `m` should only be invoked on `this`, whether explicitly or implicitly.
///
/// Tools, such as the analyzer, can provide feedback if
+///
/// * the annotation is associated with anything other than an instance member,
/// or
/// * an invocation of a member that has this annotation is used outside of an
@@ -84,6 +88,7 @@
/// optional parameter.
///
/// Tools, such as the analyzer, can provide feedback if
+///
/// * the annotation is associated with anything other than a named parameter,
/// * the annotation is associated with a named parameter in a method `m1` that
/// overrides a method `m0` and `m0` defines a named parameter with the same
diff --git a/pkg/meta/pubspec.yaml b/pkg/meta/pubspec.yaml
index d2f5506..82a1677 100644
--- a/pkg/meta/pubspec.yaml
+++ b/pkg/meta/pubspec.yaml
@@ -1,5 +1,5 @@
name: meta
-version: 0.12.0
+version: 0.12.1
author: Dart Team <misc@dartlang.org>
homepage: http://www.dartlang.org
description: >
diff --git a/pkg/pkg_files.gyp b/pkg/pkg_files.gyp
index afb09cf..9dd13e3 100644
--- a/pkg/pkg_files.gyp
+++ b/pkg/pkg_files.gyp
@@ -19,7 +19,9 @@
'action_name': 'make_pkg_files_stamp',
'inputs': [
'../tools/create_timestamp_file.py',
- '<!@(["python", "../tools/list_files.py", "\\.dart$", "."])',
+ '<!@(["python", "../tools/list_files.py",'
+ '"^(?!.*/test/).*(?<!_test)[.]dart$",'
+ '"."])',
'<(SHARED_INTERMEDIATE_DIR)/third_party_pkg_files_1.stamp',
'<(SHARED_INTERMEDIATE_DIR)/third_party_pkg_files_2.stamp',
'<(SHARED_INTERMEDIATE_DIR)/third_party_pkg_files_3.stamp',
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 6e987c4..bd091d9a 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -12,6 +12,16 @@
# while themselves doing a Debug build.
dart_debug = false
+ # Set the runtime mode. This affects how the runtime is built and what
+ # features it has. Valid values are:
+ # 'develop' (the default) - VM is built to run as a JIT with all development
+ # features enabled.
+ # 'profile' - The VM is built to run with AOT compiled code with only the
+ # CPU profiling features enabled.
+ # 'release' - The VM is built to run with AOT compiled code with no developer
+ # features enabled.
+ dart_runtime_mode = "develop"
+
# Explicitly set the target architecture in case of precompilation. Leaving
# this unspecified results in automatic target architecture detection.
# Available options are: arm, arm64, mips, x64 and ia32
@@ -24,6 +34,58 @@
]
}
+# Controls PRODUCT #define.
+config("dart_product_config") {
+ defines = []
+
+ if ((dart_runtime_mode != "develop") &&
+ (dart_runtime_mode != "profile") &&
+ (dart_runtime_mode != "release")) {
+ print("Invalid |dart_runtime_mode|")
+ assert(false)
+ }
+
+ if (dart_runtime_mode == "release") {
+ if (dart_debug) {
+ print("Debug and release mode are mutually exclusive.")
+ }
+ assert(!dart_debug)
+ defines += ["PRODUCT"]
+ }
+}
+
+# Controls DART_PRECOMPILED_RUNTIME #define.
+config("dart_precompiled_runtime_config") {
+ defines = []
+
+ if ((dart_runtime_mode != "develop") &&
+ (dart_runtime_mode != "profile") &&
+ (dart_runtime_mode != "release")) {
+ print("Invalid |dart_runtime_mode|")
+ assert(false)
+ }
+
+ if (dart_runtime_mode == "release") {
+ if (dart_debug) {
+ print("Debug and release mode are mutually exclusive.")
+ }
+ assert(!dart_debug)
+ defines += ["DART_PRECOMPILED_RUNTIME"]
+ } else if (dart_runtime_mode == "profile") {
+ if (dart_debug) {
+ print("Debug and profile mode are mutually exclusive.")
+ }
+ assert(!dart_debug)
+ defines += ["DART_PRECOMPILED_RUNTIME"]
+ }
+}
+
+# Controls DART_PRECOMPILER #define.
+config("dart_precompiler_config") {
+ defines = []
+ defines += ["DART_PRECOMPILER"]
+}
+
config("dart_config") {
defines = []
@@ -38,69 +100,8 @@
defines += [ "TARGET_ARCH_X64" ]
} else if (dart_target_arch == "ia32") {
defines += [ "TARGET_ARCH_IA32" ]
- } else {
- print("Invalid |dart_target_arch|")
- assert(false)
- }
- }
-
- if (dart_debug) {
- defines += ["DEBUG"]
- } else {
- defines += ["NDEBUG"]
- }
-
- if (is_ios || is_mac) {
- defines += ["DART_PRECOMPILER"]
- }
-
- cflags = [
- "-Werror",
- "-Wall",
- "-Wextra", # Also known as -W.
- "-Wno-unused-parameter",
- "-Wnon-virtual-dtor",
- "-Wvla",
- "-Wno-conversion-null",
- "-Woverloaded-virtual",
- "-g3",
- "-ggdb3",
- "-fno-rtti",
- "-fno-exceptions",
- ]
-
- if (dart_debug) {
- cflags += [
- "-O1",
- ]
- } else {
- cflags += [
- "-O3",
- ]
- }
-
- if (is_asan) {
- ldflags = [
- "-Wl,-u_sanitizer_options_link_helper",
- "-fsanitize=address",
- ]
- }
-}
-
-config("dart_config_no_precompiler") {
- defines = []
-
- if (dart_target_arch != "") {
- if (dart_target_arch == "arm") {
- defines += [ "TARGET_ARCH_ARM" ]
- } else if (dart_target_arch == "arm64") {
- defines += [ "TARGET_ARCH_ARM64" ]
- } else if (dart_target_arch == "mips") {
- defines += [ "TARGET_ARCH_MIPS" ]
- } else if (dart_target_arch == "x64") {
- defines += [ "TARGET_ARCH_X64" ]
- } else if (dart_target_arch == "ia32") {
- defines += [ "TARGET_ARCH_IA32" ]
+ } else if (dart_target_arch == "dbc") {
+ defines += [ "TARGET_ARCH_DBC" ]
} else {
print("Invalid |dart_target_arch|")
assert(false)
@@ -146,9 +147,10 @@
}
}
-
static_library("libdart") {
- configs += [":dart_config"]
+ configs += [":dart_config",
+ ":dart_product_config",
+ ":dart_precompiled_runtime_config"]
deps = [
"vm:libdart_lib",
"vm:libdart_vm",
@@ -173,37 +175,6 @@
]
}
-
-static_library("libdart_precompiled_runtime") {
- configs += [":dart_config_no_precompiler"]
- deps = [
- "vm:libdart_lib_precompiled_runtime",
- "vm:libdart_vm_precompiled_runtime",
- "third_party/double-conversion/src:libdouble_conversion",
- ":generate_version_cc_file",
- ]
- include_dirs = [
- ".",
- ]
- public_configs = [":dart_public_config"]
- sources = [
- "include/dart_api.h",
- "include/dart_mirrors_api.h",
- "include/dart_native_api.h",
- "include/dart_tools_api.h",
- "vm/dart_api_impl.cc",
- "vm/debugger_api_impl.cc",
- "vm/mirrors_api_impl.cc",
- "vm/native_api_impl.cc",
- "vm/version.h",
- "$target_gen_dir/version.cc",
- ]
- defines = [
- "DART_PRECOMPILED_RUNTIME",
- ]
-}
-
-
action("generate_version_cc_file") {
deps = [
":libdart_dependency_helper",
@@ -228,7 +199,9 @@
executable("libdart_dependency_helper") {
- configs += [":dart_config"]
+ configs += [":dart_config",
+ ":dart_product_config",
+ ":dart_precompiled_runtime_config"]
deps = [
"vm:libdart_lib_nosnapshot",
"vm:libdart_lib",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 20b2a8a..b5ce6e6 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -119,7 +119,7 @@
["builtin_impl_sources.gypi"])
static_library("libdart_builtin") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config", "..:dart_product_config"]
public_configs = [":libdart_builtin_config"]
deps = [
":generate_builtin_cc_file",
@@ -140,7 +140,9 @@
static_library("libdart_nosnapshot") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
deps = [
"../vm:libdart_lib_nosnapshot",
"../vm:libdart_vm_nosnapshot",
@@ -171,8 +173,44 @@
}
+static_library("libdart_nosnapshot_with_precompiler") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiler_config"]
+ deps = [
+ "../vm:libdart_lib_nosnapshot_with_precompiler",
+ "../vm:libdart_vm_nosnapshot_with_precompiler",
+ "../vm:libdart_platform",
+ "../third_party/double-conversion/src:libdouble_conversion",
+ "..:generate_version_cc_file",
+ ]
+
+ sources = [
+ "../include/dart_api.h",
+ "../include/dart_mirrors_api.h",
+ "../include/dart_native_api.h",
+ "../include/dart_tools_api.h",
+ "../vm/dart_api_impl.cc",
+ "../vm/debugger_api_impl.cc",
+ "../vm/mirrors_api_impl.cc",
+ "../vm/native_api_impl.cc",
+ "$target_gen_dir/../version.cc",
+ ]
+
+ include_dirs = [
+ "..",
+ ]
+
+ defines = [
+ "DART_SHARED_LIB",
+ ]
+}
+
+
executable("gen_snapshot") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiler_config"]
deps = [
":gen_resources_cc",
":gen_snapshot_dart_io",
@@ -180,7 +218,7 @@
":generate_io_cc_file",
":generate_io_patch_cc_file",
":libdart_builtin",
- ":libdart_nosnapshot",
+ ":libdart_nosnapshot_with_precompiler",
]
sources = [
@@ -207,7 +245,9 @@
source_set("libdart_embedder_noio") {
- configs += ["..:dart_config",]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
deps = [
"..:libdart",
"../vm:libdart_platform",
@@ -224,7 +264,9 @@
# A source set for the implementation of 'dart:io' library
# (without secure sockets) suitable for linking with gen_snapshot.
source_set("gen_snapshot_dart_io") {
- configs += ["..:dart_config",]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiler_config"]
deps = [
"//third_party/zlib",
@@ -263,7 +305,9 @@
# A source set for the implementation of 'dart:io' library
# (without secure sockets).
source_set("embedded_dart_io") {
- configs += ["..:dart_config",]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
custom_sources_filter = [
"*_test.cc",
@@ -285,7 +329,9 @@
"Security.framework",
]
} else {
- defines = [ "DART_IO_SECURE_SOCKET_DISABLED" ]
+ deps = [
+ "../../third_party/boringssl",
+ ]
}
sources = io_impl_sources_gypi.sources + builtin_impl_sources_gypi.sources
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index da8354e..0018712 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -677,41 +677,6 @@
]
},
{
- # dart_product binary.
- 'target_name': 'dart_product',
- 'type': 'executable',
- 'dependencies': [
- 'bin/zlib.gyp:zlib_dart',
- 'libdart',
- 'libdart_builtin',
- 'libdart_io',
- ],
- 'include_dirs': [
- '..',
- '../../third_party/', # Zlib
- ],
- 'defines': [
- 'DART_PRODUCT_BINARY',
- ],
- 'sources': [
- 'main.cc',
- 'builtin.h',
- 'builtin_common.cc',
- 'builtin_natives.cc',
- 'builtin_nolib.cc',
- 'io_natives.h',
- 'observatory_assets_empty.cc',
- 'snapshot_empty.cc',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'link_settings': {
- 'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib', '-lwinmm.lib' ],
- },
- }],
- ],
- },
- {
# dart binary with a snapshot of corelibs built in.
'target_name': 'dart',
'type': 'executable',
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 2f64b77..59ccec3 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -822,20 +822,6 @@
// Dart native extension scheme.
const _DART_EXT = 'dart-ext:';
-String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension";
-
-
-String _platformExtensionFileName(String name) {
- var extension = _nativeLibraryExtension();
-
- if (_isWindows) {
- return '$name.$extension';
- } else {
- return 'lib$name.$extension';
- }
-}
-
-
// Returns either a file path or a URI starting with http[s]:, as a String.
String _filePathFromUri(String userUri) {
var uri = Uri.parse(userUri);
@@ -898,11 +884,9 @@
name = userUri.substring(index + 1);
path = userUri.substring(0, index + 1);
}
-
path = _filePathFromUri(path);
- var filename = _platformExtensionFileName(name);
- return [path, filename, name];
+ return [path, name];
}
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index ba45a73..96280df 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -30,7 +30,6 @@
V(Builtin_LoadSource, 4) \
V(Builtin_AsyncLoadError, 3) \
V(Builtin_DoneLoading, 0) \
- V(Builtin_NativeLibraryExtension, 0) \
V(Builtin_GetCurrentDirectory, 0) \
diff --git a/runtime/bin/dart_entries.txt b/runtime/bin/dart_entries.txt
new file mode 100644
index 0000000..ceea4fa
--- /dev/null
+++ b/runtime/bin/dart_entries.txt
@@ -0,0 +1 @@
+dart:vmservice_io,::,main
diff --git a/runtime/bin/dart_product_entries.txt b/runtime/bin/dart_product_entries.txt
new file mode 100644
index 0000000..d8825d2
--- /dev/null
+++ b/runtime/bin/dart_product_entries.txt
@@ -0,0 +1,27 @@
+dart:_builtin,::,_getMainClosure
+dart:_builtin,::,_getPrintClosure
+dart:_builtin,::,_getUriBaseClosure
+dart:_builtin,::,_resolveUri
+dart:_builtin,::,_setWorkingDirectory
+dart:_builtin,::,_setPackageRoot
+dart:_builtin,::,_loadPackagesMap
+dart:_builtin,::,_loadDataAsync
+dart:io,::,_makeUint8ListView
+dart:io,::,_makeDatagram
+dart:io,::,_setupHooks
+dart:io,::,_getWatchSignalInternal
+dart:io,CertificateException,CertificateException.
+dart:io,Directory,Directory.
+dart:io,File,File.
+dart:io,FileSystemException,FileSystemException.
+dart:io,HandshakeException,HandshakeException.
+dart:io,Link,Link.
+dart:io,OSError,OSError.
+dart:io,TlsException,TlsException.
+dart:io,X509Certificate,X509Certificate._
+dart:io,_ExternalBuffer,set:data
+dart:io,_Platform,set:_nativeScript
+dart:io,_ProcessStartStatus,set:_errorCode
+dart:io,_ProcessStartStatus,set:_errorMessage
+dart:io,_SecureFilterImpl,get:ENCRYPTED_SIZE
+dart:io,_SecureFilterImpl,get:SIZE
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 764c00e..e180479 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -180,6 +180,17 @@
}
+void* DartUtils::MapExecutable(const char* name, intptr_t* len) {
+ File* file = File::Open(name, File::kRead);
+ if (file == NULL) {
+ return NULL;
+ }
+ void* addr = file->MapExecutable(len);
+ file->Release();
+ return addr;
+}
+
+
void* DartUtils::OpenFile(const char* name, bool write) {
File* file = File::Open(name, write ? File::kWriteTruncate : File::kRead);
return reinterpret_cast<void*>(file);
@@ -222,7 +233,8 @@
void DartUtils::CloseFile(void* stream) {
- delete reinterpret_cast<File*>(stream);
+ File* file = reinterpret_cast<File*>(stream);
+ file->Release();
}
@@ -450,15 +462,20 @@
if (Dart_IsError(path_parts)) {
return path_parts;
}
+#if defined(DEBUG)
+ intptr_t path_parts_length;
+ result = Dart_ListLength(path_parts, &path_parts_length);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ ASSERT(path_parts_length == 2);
+#endif
const char* extension_directory = NULL;
Dart_StringToCString(Dart_ListGetAt(path_parts, 0), &extension_directory);
- const char* extension_filename = NULL;
- Dart_StringToCString(Dart_ListGetAt(path_parts, 1), &extension_filename);
const char* extension_name = NULL;
- Dart_StringToCString(Dart_ListGetAt(path_parts, 2), &extension_name);
+ Dart_StringToCString(Dart_ListGetAt(path_parts, 1), &extension_name);
return Extensions::LoadExtension(extension_directory,
- extension_filename,
extension_name,
library);
}
@@ -619,17 +636,6 @@
}
-void FUNCTION_NAME(Builtin_NativeLibraryExtension)(Dart_NativeArguments args) {
- const char* suffix = Platform::LibraryExtension();
- ASSERT(suffix != NULL);
- Dart_Handle res = Dart_NewStringFromCString(suffix);
- if (Dart_IsError(res)) {
- Dart_PropagateError(res);
- }
- Dart_SetReturnValue(args, res);
-}
-
-
void FUNCTION_NAME(Builtin_GetCurrentDirectory)(Dart_NativeArguments args) {
const char* current = Directory::Current();
if (current != NULL) {
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index f9a6d50..ed63c7c 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -115,6 +115,7 @@
static bool IsDartIOLibURL(const char* url_name);
static bool IsDartBuiltinLibURL(const char* url_name);
static bool IsHttpSchemeURL(const char* url_name);
+ static void* MapExecutable(const char* name, intptr_t* file_len);
static void* OpenFile(const char* name, bool write);
static void ReadFile(const uint8_t** data, intptr_t* file_len, void* stream);
static void WriteFile(const void* buffer, intptr_t num_bytes, void* stream);
@@ -600,6 +601,69 @@
~ScopedBlockingCall() {
Dart_ThreadEnableProfiling();
}
+
+ private:
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCall);
+};
+
+
+// Where the argument to the constructor is the handle for an object
+// implementing List<int>, this class creates a scope in which the memory
+// backing the list can be accessed.
+//
+// Do not make Dart_ API calls while in a ScopedMemBuffer.
+// Do not call Dart_PropagateError while in a ScopedMemBuffer.
+class ScopedMemBuffer {
+ public:
+ explicit ScopedMemBuffer(Dart_Handle object) {
+ if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Argument is not a List<int>"));
+ }
+
+ uint8_t* bytes = NULL;
+ intptr_t bytes_len = 0;
+ bool is_typed_data = false;
+ if (Dart_IsTypedData(object)) {
+ is_typed_data = true;
+ Dart_TypedData_Type typ;
+ ThrowIfError(Dart_TypedDataAcquireData(
+ object,
+ &typ,
+ reinterpret_cast<void**>(&bytes),
+ &bytes_len));
+ } else {
+ ASSERT(Dart_IsList(object));
+ ThrowIfError(Dart_ListLength(object, &bytes_len));
+ bytes = Dart_ScopeAllocate(bytes_len);
+ ASSERT(bytes != NULL);
+ ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len));
+ }
+
+ object_ = object;
+ bytes_ = bytes;
+ bytes_len_ = bytes_len;
+ is_typed_data_ = is_typed_data;
+ }
+
+ ~ScopedMemBuffer() {
+ if (is_typed_data_) {
+ ThrowIfError(Dart_TypedDataReleaseData(object_));
+ }
+ }
+
+ uint8_t* get() const { return bytes_; }
+ intptr_t length() const { return bytes_len_; }
+
+ private:
+ Dart_Handle object_;
+ uint8_t* bytes_;
+ intptr_t bytes_len_;
+ bool is_typed_data_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(ScopedMemBuffer);
};
} // namespace bin
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index 982a4be..bb3173f 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -7,6 +7,7 @@
#include "bin/directory.h"
#include "bin/dartutils.h"
+#include "bin/log.h"
#include "include/dart_api.h"
#include "platform/assert.h"
@@ -139,6 +140,61 @@
}
+static const int kAsyncDirectoryListerFieldIndex = 0;
+
+
+void FUNCTION_NAME(Directory_GetAsyncDirectoryListerPointer)(
+ Dart_NativeArguments args) {
+ AsyncDirectoryListing* listing;
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_GetNativeInstanceField(
+ dart_this,
+ kAsyncDirectoryListerFieldIndex,
+ reinterpret_cast<intptr_t*>(&listing)));
+ if (listing != NULL) {
+ intptr_t listing_pointer = reinterpret_cast<intptr_t>(listing);
+ // Increment the listing's reference count. This native should only be
+ // be called when we are about to send the AsyncDirectoryListing* to the
+ // IO service.
+ listing->Retain();
+ Dart_SetReturnValue(args, Dart_NewInteger(listing_pointer));
+ }
+}
+
+
+static void ReleaseListing(void* isolate_callback_data,
+ Dart_WeakPersistentHandle handle,
+ void* peer) {
+ AsyncDirectoryListing* listing =
+ reinterpret_cast<AsyncDirectoryListing*>(peer);
+ listing->Release();
+}
+
+
+void FUNCTION_NAME(Directory_SetAsyncDirectoryListerPointer)(
+ Dart_NativeArguments args) {
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ intptr_t listing_pointer =
+ DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+ AsyncDirectoryListing* listing =
+ reinterpret_cast<AsyncDirectoryListing*>(listing_pointer);
+ Dart_NewWeakPersistentHandle(
+ dart_this,
+ reinterpret_cast<void*>(listing),
+ sizeof(*listing),
+ ReleaseListing);
+ Dart_Handle result = Dart_SetNativeInstanceField(
+ dart_this,
+ kAsyncDirectoryListerFieldIndex,
+ listing_pointer);
+ if (Dart_IsError(result)) {
+ Log::PrintErr("SetAsyncDirectoryListerPointer failed\n");
+ Dart_PropagateError(result);
+ }
+}
+
+
CObject* Directory::CreateRequest(const CObjectArray& request) {
if ((request.Length() == 1) && request[0]->IsString()) {
CObjectString path(request[0]);
@@ -226,7 +282,7 @@
if (dir_listing->error()) {
// Report error now, so we capture the correct OSError.
CObject* err = CObject::NewOSError();
- delete dir_listing;
+ dir_listing->Release();
CObjectArray* error = new CObjectArray(CObject::NewArray(3));
error->SetAt(0, new CObjectInt32(
CObject::NewInt32(AsyncDirectoryListing::kListError)));
@@ -247,6 +303,7 @@
CObjectIntptr ptr(request[0]);
AsyncDirectoryListing* dir_listing =
reinterpret_cast<AsyncDirectoryListing*>(ptr.Value());
+ RefCntReleaseScope<AsyncDirectoryListing> rs(dir_listing);
if (dir_listing->IsEmpty()) {
return new CObjectArray(CObject::NewArray(0));
}
@@ -268,7 +325,15 @@
CObjectIntptr ptr(request[0]);
AsyncDirectoryListing* dir_listing =
reinterpret_cast<AsyncDirectoryListing*>(ptr.Value());
- delete dir_listing;
+ RefCntReleaseScope<AsyncDirectoryListing> rs(dir_listing);
+
+ // We have retained a reference to the listing here. Therefore the listing's
+ // destructor can't be running. Since no further requests are dispatched by
+ // the Dart code after an async stop call, this PopAll() can't be racing
+ // with any other call on the listing. We don't do an extra Release(), and
+ // we don't delete the weak persistent handle. The file is closed here, but
+ // the memory for the listing will be cleaned up when the finalizer runs.
+ dir_listing->PopAll();
return new CObjectBool(CObject::Bool(true));
}
return CreateIllegalArgumentError();
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index 7a1c5d1..f455710 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -7,6 +7,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/reference_counting.h"
#include "bin/thread.h"
#include "platform/globals.h"
@@ -107,9 +108,7 @@
}
virtual ~DirectoryListing() {
- while (!IsEmpty()) {
- Pop();
- }
+ PopAll();
}
virtual bool HandleDirectory(const char* dir_name) = 0;
@@ -133,6 +132,12 @@
return top_ == NULL;
}
+ void PopAll() {
+ while (!IsEmpty()) {
+ Pop();
+ }
+ }
+
DirectoryListingEntry* top() const {
return top_;
}
@@ -166,7 +171,8 @@
};
-class AsyncDirectoryListing : public DirectoryListing {
+class AsyncDirectoryListing : public ReferenceCounted<AsyncDirectoryListing>,
+ public DirectoryListing {
public:
enum Response {
kListFile = 0,
@@ -179,9 +185,12 @@
AsyncDirectoryListing(const char* dir_name,
bool recursive,
bool follow_links)
- : DirectoryListing(dir_name, recursive, follow_links) {}
+ : ReferenceCounted(),
+ DirectoryListing(dir_name, recursive, follow_links),
+ array_(NULL),
+ index_(0),
+ length_(0) {}
- virtual ~AsyncDirectoryListing() {}
virtual bool HandleDirectory(const char* dir_name);
virtual bool HandleFile(const char* file_name);
virtual bool HandleLink(const char* file_name);
@@ -200,11 +209,13 @@
}
private:
+ virtual ~AsyncDirectoryListing() {}
bool AddFileSystemEntityToResponse(Response response, const char* arg);
CObjectArray* array_;
intptr_t index_;
intptr_t length_;
+ friend class ReferenceCounted<AsyncDirectoryListing>;
DISALLOW_IMPLICIT_CONSTRUCTORS(AsyncDirectoryListing);
};
@@ -238,6 +249,7 @@
Dart_Handle file_type_;
Dart_Handle link_type_;
+ DISALLOW_ALLOCATION()
DISALLOW_IMPLICIT_CONSTRUCTORS(SyncDirectoryListing);
};
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index f8643ae..f98a52e 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -16,3 +16,21 @@
/* patch */ static List _list(String path, bool recursive, bool followLinks)
native "Directory_List";
}
+
+patch class _AsyncDirectoryListerOps {
+ /* patch */ factory _AsyncDirectoryListerOps(int pointer) =>
+ new _AsyncDirectoryListerOpsImpl(pointer);
+}
+
+class _AsyncDirectoryListerOpsImpl extends NativeFieldWrapperClass1
+ implements _AsyncDirectoryListerOps {
+ _AsyncDirectoryListerOpsImpl._();
+
+ factory _AsyncDirectoryListerOpsImpl(int pointer)
+ => new _AsyncDirectoryListerOpsImpl._().._setPointer(pointer);
+
+ void _setPointer(int pointer)
+ native "Directory_SetAsyncDirectoryListerPointer";
+ int getPointer()
+ native "Directory_GetAsyncDirectoryListerPointer";
+}
diff --git a/runtime/bin/directory_unsupported.cc b/runtime/bin/directory_unsupported.cc
index 7e82bdd..1b1abd2 100644
--- a/runtime/bin/directory_unsupported.cc
+++ b/runtime/bin/directory_unsupported.cc
@@ -64,6 +64,20 @@
"Directory is not supported on this platform"));
}
+
+void FUNCTION_NAME(Directory_GetAsyncDirectoryListerPointer)(
+ Dart_NativeArguments args) {
+ Dart_ThrowException(DartUtils::NewInternalError(
+ "Directory is not supported on this platform"));
+}
+
+
+void FUNCTION_NAME(Directory_SetAsyncDirectoryListerPointer)(
+ Dart_NativeArguments args) {
+ Dart_ThrowException(DartUtils::NewInternalError(
+ "Directory is not supported on this platform"));
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/extensions.cc b/runtime/bin/extensions.cc
index 7fa06fd..f4b921f 100644
--- a/runtime/bin/extensions.cc
+++ b/runtime/bin/extensions.cc
@@ -8,6 +8,7 @@
#include "bin/dartutils.h"
#include "bin/file.h"
+#include "bin/platform.h"
#include "include/dart_api.h"
#include "platform/assert.h"
#include "platform/globals.h"
@@ -16,18 +17,42 @@
namespace bin {
Dart_Handle Extensions::LoadExtension(const char* extension_directory,
- const char* extension_file,
const char* extension_name,
Dart_Handle parent_library) {
if (strncmp(extension_directory, "http://", 7) == 0 ||
strncmp(extension_directory, "https://", 8) == 0) {
return Dart_NewApiError("Cannot load native extensions over http:");
}
- const char* library_strings[] = { extension_directory, extension_file, NULL };
+
+ // For example on Linux: directory/libfoo-arm.so
+ const char* library_strings[] = {
+ extension_directory, // directory/
+ Platform::LibraryPrefix(), // lib
+ extension_name, // foo
+ "-",
+ Platform::HostArchitecture(), // arm
+ ".",
+ Platform::LibraryExtension(), // so
+ NULL,
+ };
const char* library_file = Concatenate(library_strings);
void* library_handle = LoadExtensionLibrary(library_file);
if (library_handle == NULL) {
- return GetError();
+ // Fallback on a library file name that does not specify the host
+ // architecture. For example on Linux: directory/libfoo.so
+ const char* fallback_library_strings[] = {
+ extension_directory, // directory/
+ Platform::LibraryPrefix(), // lib
+ extension_name, // foo
+ ".",
+ Platform::LibraryExtension(), // so
+ NULL,
+ };
+ const char* fallback_library_file = Concatenate(fallback_library_strings);
+ library_handle = LoadExtensionLibrary(fallback_library_file);
+ if (library_handle == NULL) {
+ return GetError();
+ }
}
const char* strings[] = { extension_name, "_Init", NULL };
diff --git a/runtime/bin/extensions.h b/runtime/bin/extensions.h
index da18615..d266303 100644
--- a/runtime/bin/extensions.h
+++ b/runtime/bin/extensions.h
@@ -16,7 +16,6 @@
// TODO(whesse): Make extension load from a relative path relative to
// the library it is in. Currently loads from current working directory.
static Dart_Handle LoadExtension(const char* extension_directory,
- const char* extension_filename,
const char* extension_name,
Dart_Handle parent_library);
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index e730b172..43e1944 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -18,14 +18,66 @@
namespace dart {
namespace bin {
+static const int kFileNativeFieldIndex = 0;
static const int kMSPerSecond = 1000;
// The file pointer has been passed into Dart as an intptr_t and it is safe
// to pull it out of Dart as a 64-bit integer, cast it to an intptr_t and
// from there to a File pointer.
-static File* GetFilePointer(Dart_Handle handle) {
- intptr_t value = DartUtils::GetIntptrValue(handle);
- return reinterpret_cast<File*>(value);
+static File* GetFile(Dart_NativeArguments args) {
+ File* file;
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_GetNativeInstanceField(
+ dart_this,
+ kFileNativeFieldIndex,
+ reinterpret_cast<intptr_t*>(&file)));
+ return file;
+}
+
+
+static void SetFile(Dart_Handle dart_this, intptr_t file_pointer) {
+ Dart_Handle result = Dart_SetNativeInstanceField(
+ dart_this,
+ kFileNativeFieldIndex,
+ file_pointer);
+ if (Dart_IsError(result)) {
+ Log::PrintErr("SetNativeInstanceField in SetFile() failed\n");
+ Dart_PropagateError(result);
+ }
+}
+
+
+void FUNCTION_NAME(File_GetPointer)(Dart_NativeArguments args) {
+ File* file = GetFile(args);
+ // If the file is already closed, GetFile() will return NULL.
+ if (file != NULL) {
+ // Increment file's reference count. File_GetPointer() should only be called
+ // when we are about to send the File* to the IO Service.
+ file->Retain();
+ }
+ intptr_t file_pointer = reinterpret_cast<intptr_t>(file);
+ Dart_SetReturnValue(args, Dart_NewInteger(file_pointer));
+}
+
+
+static void ReleaseFile(void* isolate_callback_data,
+ Dart_WeakPersistentHandle handle,
+ void* peer) {
+ File* file = reinterpret_cast<File*>(peer);
+ file->Release();
+}
+
+
+void FUNCTION_NAME(File_SetPointer)(Dart_NativeArguments args) {
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ intptr_t file_pointer =
+ DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+ File* file = reinterpret_cast<File*>(file_pointer);
+ Dart_WeakPersistentHandle handle = Dart_NewWeakPersistentHandle(
+ dart_this, reinterpret_cast<void*>(file), sizeof(*file), ReleaseFile);
+ file->SetWeakHandle(handle);
+ SetFile(dart_this, file_pointer);
}
@@ -40,8 +92,7 @@
// reading. This is to prevent the opening of directories as
// files. Directories can be opened for reading using the posix
// 'open' call.
- File* file = NULL;
- file = File::ScopedOpen(filename, file_mode);
+ File* file = File::ScopedOpen(filename, file_mode);
if (file != NULL) {
Dart_SetReturnValue(args,
Dart_NewInteger(reinterpret_cast<intptr_t>(file)));
@@ -60,22 +111,20 @@
void FUNCTION_NAME(File_Close)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
- delete file;
+ file->DeleteWeakHandle(Dart_CurrentIsolate());
+ file->Release();
+
+ // NULL-out the now potentially dangling pointer.
+ Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
+ SetFile(dart_this, 0);
Dart_SetReturnValue(args, Dart_NewInteger(0));
}
-void FUNCTION_NAME(File_GetFD)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
- ASSERT(file != NULL);
- Dart_SetReturnValue(args, Dart_NewInteger(file->GetFD()));
-}
-
-
void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
uint8_t buffer;
int64_t bytes_read = file->Read(reinterpret_cast<void*>(&buffer), 1);
@@ -90,7 +139,7 @@
void FUNCTION_NAME(File_WriteByte)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
int64_t byte = 0;
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &byte)) {
@@ -109,7 +158,7 @@
void FUNCTION_NAME(File_Read)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
Dart_Handle length_object = Dart_GetNativeArgument(args, 1);
int64_t length = 0;
@@ -150,7 +199,7 @@
void FUNCTION_NAME(File_ReadInto)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
ASSERT(Dart_IsList(buffer_obj));
@@ -185,7 +234,7 @@
void FUNCTION_NAME(File_WriteFrom)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
@@ -233,7 +282,7 @@
void FUNCTION_NAME(File_Position)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
intptr_t return_value = file->Position();
if (return_value >= 0) {
@@ -245,7 +294,7 @@
void FUNCTION_NAME(File_SetPosition)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
int64_t position = 0;
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &position)) {
@@ -262,7 +311,7 @@
void FUNCTION_NAME(File_Truncate)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
int64_t length = 0;
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &length)) {
@@ -279,7 +328,7 @@
void FUNCTION_NAME(File_Length)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
int64_t return_value = file->Length();
if (return_value >= 0) {
@@ -315,7 +364,7 @@
void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
if (file->Flush()) {
Dart_SetReturnValue(args, Dart_True());
@@ -326,7 +375,7 @@
void FUNCTION_NAME(File_Lock)(Dart_NativeArguments args) {
- File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
+ File* file = GetFile(args);
ASSERT(file != NULL);
int64_t lock;
int64_t start;
@@ -704,9 +753,16 @@
intptr_t return_value = -1;
if ((request.Length() == 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- delete file;
+ RefCntReleaseScope<File> rs(file);
return_value = 0;
+ // We have retained a reference to the file here. Therefore the file's
+ // destructor can't be running. Since no further requests are dispatched by
+ // the Dart code after an async close call, this Close() can't be racing
+ // with any other call on the file. We don't do an extra Release(), and we
+ // don't delete the weak persistent handle. The file is closed here, but the
+ // memory will be cleaned up when the finalizer runs.
+ ASSERT(!file->IsClosed());
+ file->Close();
}
return new CObjectIntptr(CObject::NewIntptr(return_value));
}
@@ -715,7 +771,7 @@
CObject* File::PositionRequest(const CObjectArray& request) {
if ((request.Length() == 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
+ RefCntReleaseScope<File> rs(file);
if (!file->IsClosed()) {
intptr_t return_value = file->Position();
if (return_value >= 0) {
@@ -732,20 +788,22 @@
CObject* File::SetPositionRequest(const CObjectArray& request) {
- if ((request.Length() == 2) &&
- request[0]->IsIntptr() &&
- request[1]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t position = CObjectInt32OrInt64ToInt64(request[1]);
- if (file->SetPosition(position)) {
- return CObject::True();
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t position = CObjectInt32OrInt64ToInt64(request[1]);
+ if (file->SetPosition(position)) {
+ return CObject::True();
+ } else {
+ return CObject::NewOSError();
+ }
} else {
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
@@ -753,20 +811,22 @@
CObject* File::TruncateRequest(const CObjectArray& request) {
- if ((request.Length() == 2) &&
- request[0]->IsIntptr() &&
- request[1]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
- if (file->Truncate(length)) {
- return CObject::True();
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
+ if (file->Truncate(length)) {
+ return CObject::True();
+ } else {
+ return CObject::NewOSError();
+ }
} else {
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
@@ -776,7 +836,7 @@
CObject* File::LengthRequest(const CObjectArray& request) {
if ((request.Length() == 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
+ RefCntReleaseScope<File> rs(file);
if (!file->IsClosed()) {
int64_t return_value = file->Length();
if (return_value >= 0) {
@@ -823,7 +883,7 @@
CObject* File::FlushRequest(const CObjectArray& request) {
if ((request.Length() == 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
+ RefCntReleaseScope<File> rs(file);
if (!file->IsClosed()) {
if (file->Flush()) {
return CObject::True();
@@ -841,7 +901,7 @@
CObject* File::ReadByteRequest(const CObjectArray& request) {
if ((request.Length() == 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
+ RefCntReleaseScope<File> rs(file);
if (!file->IsClosed()) {
uint8_t buffer;
int64_t bytes_read = file->Read(reinterpret_cast<void*>(&buffer), 1);
@@ -861,22 +921,24 @@
CObject* File::WriteByteRequest(const CObjectArray& request) {
- if ((request.Length() == 2) &&
- request[0]->IsIntptr() &&
- request[1]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t byte = CObjectInt32OrInt64ToInt64(request[1]);
- uint8_t buffer = static_cast<uint8_t>(byte & 0xff);
- bool success = file->WriteFully(reinterpret_cast<void*>(&buffer), 1);
- if (success) {
- return new CObjectInt64(CObject::NewInt64(1));
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t byte = CObjectInt32OrInt64ToInt64(request[1]);
+ uint8_t buffer = static_cast<uint8_t>(byte & 0xff);
+ bool success = file->WriteFully(reinterpret_cast<void*>(&buffer), 1);
+ if (success) {
+ return new CObjectInt64(CObject::NewInt64(1));
+ } else {
+ return CObject::NewOSError();
+ }
} else {
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
@@ -884,31 +946,33 @@
CObject* File::ReadRequest(const CObjectArray& request) {
- if ((request.Length() == 2) &&
- request[0]->IsIntptr() &&
- request[1]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
- Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
- ASSERT(io_buffer != NULL);
- uint8_t* data = io_buffer->value.as_external_typed_data.data;
- int64_t bytes_read = file->Read(data, length);
- if (bytes_read >= 0) {
- CObjectExternalUint8Array* external_array =
- new CObjectExternalUint8Array(io_buffer);
- external_array->SetLength(bytes_read);
- CObjectArray* result = new CObjectArray(CObject::NewArray(2));
- result->SetAt(0, new CObjectIntptr(CObject::NewInt32(0)));
- result->SetAt(1, external_array);
- return result;
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
+ Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
+ ASSERT(io_buffer != NULL);
+ uint8_t* data = io_buffer->value.as_external_typed_data.data;
+ int64_t bytes_read = file->Read(data, length);
+ if (bytes_read >= 0) {
+ CObjectExternalUint8Array* external_array =
+ new CObjectExternalUint8Array(io_buffer);
+ external_array->SetLength(bytes_read);
+ CObjectArray* result = new CObjectArray(CObject::NewArray(2));
+ result->SetAt(0, new CObjectIntptr(CObject::NewInt32(0)));
+ result->SetAt(1, external_array);
+ return result;
+ } else {
+ CObject::FreeIOBufferData(io_buffer);
+ return CObject::NewOSError();
+ }
} else {
- CObject::FreeIOBufferData(io_buffer);
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
@@ -916,32 +980,34 @@
CObject* File::ReadIntoRequest(const CObjectArray& request) {
- if ((request.Length() == 2) &&
- request[0]->IsIntptr() &&
- request[1]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
- Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
- ASSERT(io_buffer != NULL);
- uint8_t* data = io_buffer->value.as_external_typed_data.data;
- int64_t bytes_read = file->Read(data, length);
- if (bytes_read >= 0) {
- CObjectExternalUint8Array* external_array =
- new CObjectExternalUint8Array(io_buffer);
- external_array->SetLength(bytes_read);
- CObjectArray* result = new CObjectArray(CObject::NewArray(3));
- result->SetAt(0, new CObjectIntptr(CObject::NewInt32(0)));
- result->SetAt(1, new CObjectInt64(CObject::NewInt64(bytes_read)));
- result->SetAt(2, external_array);
- return result;
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
+ Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
+ ASSERT(io_buffer != NULL);
+ uint8_t* data = io_buffer->value.as_external_typed_data.data;
+ int64_t bytes_read = file->Read(data, length);
+ if (bytes_read >= 0) {
+ CObjectExternalUint8Array* external_array =
+ new CObjectExternalUint8Array(io_buffer);
+ external_array->SetLength(bytes_read);
+ CObjectArray* result = new CObjectArray(CObject::NewArray(3));
+ result->SetAt(0, new CObjectIntptr(CObject::NewInt32(0)));
+ result->SetAt(1, new CObjectInt64(CObject::NewInt64(bytes_read)));
+ result->SetAt(2, external_array);
+ return result;
+ } else {
+ CObject::FreeIOBufferData(io_buffer);
+ return CObject::NewOSError();
+ }
} else {
- CObject::FreeIOBufferData(io_buffer);
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
@@ -974,46 +1040,49 @@
CObject* File::WriteFromRequest(const CObjectArray& request) {
- if ((request.Length() == 4) &&
- request[0]->IsIntptr() &&
- (request[1]->IsTypedData() || request[1]->IsArray()) &&
- request[2]->IsInt32OrInt64() &&
- request[3]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t start = CObjectInt32OrInt64ToInt64(request[2]);
- int64_t end = CObjectInt32OrInt64ToInt64(request[3]);
- int64_t length = end - start;
- uint8_t* buffer_start;
- if (request[1]->IsTypedData()) {
- CObjectTypedData typed_data(request[1]);
- start = start * SizeInBytes(typed_data.Type());
- length = length * SizeInBytes(typed_data.Type());
- buffer_start = typed_data.Buffer() + start;
- } else {
- CObjectArray array(request[1]);
- buffer_start = Dart_ScopeAllocate(length);
- for (int i = 0; i < length; i++) {
- if (array[i + start]->IsInt32OrInt64()) {
- int64_t value = CObjectInt32OrInt64ToInt64(array[i + start]);
- buffer_start[i] = static_cast<uint8_t>(value & 0xFF);
- } else {
- // Unsupported type.
- return CObject::IllegalArgumentError();
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 4) &&
+ (request[1]->IsTypedData() || request[1]->IsArray()) &&
+ request[2]->IsInt32OrInt64() &&
+ request[3]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t start = CObjectInt32OrInt64ToInt64(request[2]);
+ int64_t end = CObjectInt32OrInt64ToInt64(request[3]);
+ int64_t length = end - start;
+ uint8_t* buffer_start;
+ if (request[1]->IsTypedData()) {
+ CObjectTypedData typed_data(request[1]);
+ start = start * SizeInBytes(typed_data.Type());
+ length = length * SizeInBytes(typed_data.Type());
+ buffer_start = typed_data.Buffer() + start;
+ } else {
+ CObjectArray array(request[1]);
+ buffer_start = Dart_ScopeAllocate(length);
+ for (int i = 0; i < length; i++) {
+ if (array[i + start]->IsInt32OrInt64()) {
+ int64_t value = CObjectInt32OrInt64ToInt64(array[i + start]);
+ buffer_start[i] = static_cast<uint8_t>(value & 0xFF);
+ } else {
+ // Unsupported type.
+ return CObject::IllegalArgumentError();
+ }
}
+ start = 0;
}
- start = 0;
- }
- bool success =
- file->WriteFully(reinterpret_cast<void*>(buffer_start), length);
- if (success) {
- return new CObjectInt64(CObject::NewInt64(length));
+ bool success =
+ file->WriteFully(reinterpret_cast<void*>(buffer_start), length);
+ if (success) {
+ return new CObjectInt64(CObject::NewInt64(length));
+ } else {
+ return CObject::NewOSError();
+ }
} else {
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
@@ -1137,24 +1206,27 @@
CObject* File::LockRequest(const CObjectArray& request) {
- if ((request.Length() == 4) &&
- request[0]->IsIntptr() &&
- request[1]->IsInt32OrInt64() &&
- request[2]->IsInt32OrInt64() &&
- request[3]->IsInt32OrInt64()) {
+ if ((request.Length() >= 1) && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
- ASSERT(file != NULL);
- if (!file->IsClosed()) {
- int64_t lock = CObjectInt32OrInt64ToInt64(request[1]);
- int64_t start = CObjectInt32OrInt64ToInt64(request[2]);
- int64_t end = CObjectInt32OrInt64ToInt64(request[3]);
- if (file->Lock(static_cast<File::LockType>(lock), start, end)) {
- return CObject::True();
+ RefCntReleaseScope<File> rs(file);
+ if ((request.Length() == 4) &&
+ request[1]->IsInt32OrInt64() &&
+ request[2]->IsInt32OrInt64() &&
+ request[3]->IsInt32OrInt64()) {
+ if (!file->IsClosed()) {
+ int64_t lock = CObjectInt32OrInt64ToInt64(request[1]);
+ int64_t start = CObjectInt32OrInt64ToInt64(request[2]);
+ int64_t end = CObjectInt32OrInt64ToInt64(request[3]);
+ if (file->Lock(static_cast<File::LockType>(lock), start, end)) {
+ return CObject::True();
+ } else {
+ return CObject::NewOSError();
+ }
} else {
- return CObject::NewOSError();
+ return CObject::FileClosedError();
}
} else {
- return CObject::FileClosedError();
+ return CObject::IllegalArgumentError();
}
}
return CObject::IllegalArgumentError();
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 3c8255f..2c153bc 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -12,6 +12,8 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/log.h"
+#include "bin/reference_counting.h"
namespace dart {
namespace bin {
@@ -19,7 +21,7 @@
// Forward declaration.
class FileHandle;
-class File {
+class File : public ReferenceCounted<File> {
public:
enum FileOpenMode {
kRead = 0,
@@ -82,10 +84,10 @@
kLockMax = 2
};
- ~File();
-
intptr_t GetFD();
+ void* MapExecutable(intptr_t* num_bytes);
+
// Read/Write attempt to transfer num_bytes to/from buffer. It returns
// the number of bytes read/written.
int64_t Read(void* buffer, int64_t num_bytes);
@@ -124,6 +126,26 @@
// Returns whether the file has been closed.
bool IsClosed();
+ // Calls the platform-specific functions to close the file.
+ void Close();
+
+ // Returns the weak persistent handle for the File's Dart wrapper.
+ Dart_WeakPersistentHandle WeakHandle() const { return weak_handle_; }
+
+ // Set the weak persistent handle for the File's Dart wrapper.
+ void SetWeakHandle(Dart_WeakPersistentHandle handle) {
+ ASSERT(weak_handle_ == NULL);
+ weak_handle_ = handle;
+ }
+
+ // Deletes the weak persistent handle for the File's Dart wrapper. Call
+ // when the file is explicitly closed and the finalizer is no longer
+ // needed.
+ void DeleteWeakHandle(Dart_Isolate isolate) {
+ Dart_DeleteWeakPersistentHandle(isolate, weak_handle_);
+ weak_handle_ = NULL;
+ }
+
// Open the file with the given path. The file is always opened for
// reading. If mode contains kWrite the file is opened for both
// reading and writing. If mode contains kWrite and the file does
@@ -190,8 +212,12 @@
static CObject* LockRequest(const CObjectArray& request);
private:
- explicit File(FileHandle* handle) : handle_(handle) { }
- void Close();
+ explicit File(FileHandle* handle) :
+ ReferenceCounted(),
+ handle_(handle),
+ weak_handle_(NULL) {}
+
+ ~File();
static File* FileOpenW(const wchar_t* system_name, FileOpenMode mode);
@@ -200,6 +226,12 @@
// FileHandle is an OS specific class which stores data about the file.
FileHandle* handle_; // OS specific handle for the file.
+ // We retain the weak handle because we can do cleanup eagerly when Dart code
+ // calls closeSync(). In that case, we delete the weak handle so that the
+ // finalizer doesn't run.
+ Dart_WeakPersistentHandle weak_handle_;
+
+ friend class ReferenceCounted<File>;
DISALLOW_COPY_AND_ASSIGN(File);
};
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index a115715..8b86121 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -10,6 +10,7 @@
#include <errno.h> // NOLINT
#include <fcntl.h> // NOLINT
#include <libgen.h> // NOLINT
+#include <sys/mman.h> // NOLINT
#include <sys/sendfile.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <sys/types.h> // NOLINT
@@ -39,7 +40,9 @@
File::~File() {
- Close();
+ if (!IsClosed()) {
+ Close();
+ }
delete handle_;
}
@@ -75,6 +78,22 @@
}
+void* File::MapExecutable(intptr_t* len) {
+ ASSERT(handle_->fd() >= 0);
+
+ intptr_t length = Length();
+ void* addr = mmap(0, length,
+ PROT_READ | PROT_EXEC, MAP_PRIVATE,
+ handle_->fd(), 0);
+ if (addr == MAP_FAILED) {
+ *len = -1;
+ } else {
+ *len = length;
+ }
+ return addr;
+}
+
+
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
@@ -197,10 +216,7 @@
File* File::OpenStdio(int fd) {
- if ((fd < 0) || (2 < fd)) {
- return NULL;
- }
- return new File(new FileHandle(fd));
+ return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
}
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 3099715..2e47d74 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -10,6 +10,7 @@
#include <errno.h> // NOLINT
#include <fcntl.h> // NOLINT
#include <libgen.h> // NOLINT
+#include <sys/mman.h> // NOLINT
#include <sys/sendfile.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <sys/types.h> // NOLINT
@@ -38,7 +39,9 @@
File::~File() {
- Close();
+ if (!IsClosed()) {
+ Close();
+ }
delete handle_;
}
@@ -73,6 +76,21 @@
}
+void* File::MapExecutable(intptr_t* len) {
+ ASSERT(handle_->fd() >= 0);
+ intptr_t length = Length();
+ void* addr = mmap(0, length,
+ PROT_READ | PROT_EXEC, MAP_PRIVATE,
+ handle_->fd(), 0);
+ if (addr == MAP_FAILED) {
+ *len = -1;
+ } else {
+ *len = length;
+ }
+ return addr;
+}
+
+
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
@@ -155,8 +173,8 @@
// Report errors for non-regular files.
struct stat64 st;
if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
- // Only accept regular files and character devices.
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
+ // Only accept regular files, character devices, and pipes.
+ if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
return NULL;
}
@@ -196,10 +214,7 @@
File* File::OpenStdio(int fd) {
- if ((fd < 0) || (2 < fd)) {
- return NULL;
- }
- return new File(new FileHandle(fd));
+ return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
}
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 81412f6..941d419 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -12,6 +12,7 @@
#include <fcntl.h> // NOLINT
#include <libgen.h> // NOLINT
#include <limits.h> // NOLINT
+#include <sys/mman.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
@@ -40,7 +41,9 @@
File::~File() {
- Close();
+ if (!IsClosed()) {
+ Close();
+ }
delete handle_;
}
@@ -76,6 +79,21 @@
}
+void* File::MapExecutable(intptr_t* len) {
+ ASSERT(handle_->fd() >= 0);
+ intptr_t length = Length();
+ void* addr = mmap(0, length,
+ PROT_READ | PROT_EXEC, MAP_PRIVATE,
+ handle_->fd(), 0);
+ if (addr == MAP_FAILED) {
+ *len = -1;
+ } else {
+ *len = length;
+ }
+ return addr;
+}
+
+
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
@@ -158,8 +176,8 @@
// Report errors for non-regular files.
struct stat st;
if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
- // Only accept regular files and character devices.
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
+ // Only accept regular files, character devices, and pipes.
+ if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
return NULL;
}
@@ -199,10 +217,7 @@
File* File::OpenStdio(int fd) {
- if ((fd < 0) || (2 < fd)) {
- return NULL;
- }
- return new File(new FileHandle(fd));
+ return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
}
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 479bb9f..a3d42e8 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -22,24 +22,34 @@
}
-patch class _RandomAccessFile {
- /* patch */ static int _close(int id) native "File_Close";
- /* patch */ static int _getFD(int id) native "File_GetFD";
- /* patch */ static _readByte(int id) native "File_ReadByte";
- /* patch */ static _read(int id, int bytes) native "File_Read";
- /* patch */ static _readInto(int id, List<int> buffer, int start, int end)
- native "File_ReadInto";
- /* patch */ static _writeByte(int id, int value) native "File_WriteByte";
- /* patch */ static _writeFrom(int id, List<int> buffer, int start, int end)
- native "File_WriteFrom";
- /* patch */ static _position(int id) native "File_Position";
- /* patch */ static _setPosition(int id, int position)
- native "File_SetPosition";
- /* patch */ static _truncate(int id, int length) native "File_Truncate";
- /* patch */ static _length(int id) native "File_Length";
- /* patch */ static _flush(int id) native "File_Flush";
- /* patch */ static _lock(int id, int lock, int start, int end)
- native "File_Lock";
+patch class _RandomAccessFileOps {
+ /* patch */ factory _RandomAccessFileOps(int pointer)
+ => new _RandomAccessFileOpsImpl(pointer);
+}
+
+
+class _RandomAccessFileOpsImpl extends NativeFieldWrapperClass1
+ implements _RandomAccessFileOps {
+ _RandomAccessFileOpsImpl._();
+
+ factory _RandomAccessFileOpsImpl(int pointer)
+ => new _RandomAccessFileOpsImpl._().._setPointer(pointer);
+
+ void _setPointer(int pointer) native "File_SetPointer";
+
+ int getPointer() native "File_GetPointer";
+ int close() native "File_Close";
+ readByte() native "File_ReadByte";
+ read(int bytes) native "File_Read";
+ readInto(List<int> buffer, int start, int end) native "File_ReadInto";
+ writeByte(int value) native "File_WriteByte";
+ writeFrom(List<int> buffer, int start, int end) native "File_WriteFrom";
+ position() native "File_Position";
+ setPosition(int position) native "File_SetPosition";
+ truncate(int length) native "File_Truncate";
+ length() native "File_Length";
+ flush() native "File_Flush";
+ lock(int lock, int start, int end) native "File_Lock";
}
diff --git a/runtime/bin/file_test.cc b/runtime/bin/file_test.cc
index 518e6e5..4c2c0d1 100644
--- a/runtime/bin/file_test.cc
+++ b/runtime/bin/file_test.cc
@@ -32,7 +32,7 @@
buffer[13] = '\0';
EXPECT_STREQ("// Copyright ", buffer);
EXPECT(!file->WriteByte(1)); // Cannot write to a read-only file.
- delete file;
+ file->Release();
}
@@ -42,7 +42,7 @@
File* file = File::Open(kFilename, File::kRead);
EXPECT(file != NULL);
EXPECT_EQ(42, file->Length());
- delete file;
+ file->Release();
}
@@ -56,7 +56,7 @@
EXPECT_EQ(12, file->Position());
EXPECT(file->ReadFully(buf, 6));
EXPECT_EQ(18, file->Position());
- delete file;
+ file->Release();
}
} // namespace bin
diff --git a/runtime/bin/file_unsupported.cc b/runtime/bin/file_unsupported.cc
index 2655f77..55a88d0 100644
--- a/runtime/bin/file_unsupported.cc
+++ b/runtime/bin/file_unsupported.cc
@@ -11,6 +11,19 @@
namespace dart {
namespace bin {
+
+void FUNCTION_NAME(File_GetPointer)(Dart_NativeArguments args) {
+ Dart_ThrowException(DartUtils::NewInternalError(
+ "File is not supported on this platform"));
+}
+
+
+void FUNCTION_NAME(File_SetPointer)(Dart_NativeArguments args) {
+ Dart_ThrowException(DartUtils::NewInternalError(
+ "File is not supported on this platform"));
+}
+
+
void FUNCTION_NAME(File_Open)(Dart_NativeArguments args) {
Dart_ThrowException(DartUtils::NewInternalError(
"File is not supported on this platform"));
@@ -29,12 +42,6 @@
}
-void FUNCTION_NAME(File_GetFD)(Dart_NativeArguments args) {
- Dart_ThrowException(DartUtils::NewInternalError(
- "File is not supported on this platform"));
-}
-
-
void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) {
Dart_ThrowException(DartUtils::NewInternalError(
"File is not supported on this platform"));
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 054370a..db3aef8 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -38,7 +38,9 @@
File::~File() {
- Close();
+ if (!IsClosed()) {
+ Close();
+ }
delete handle_;
}
@@ -71,6 +73,12 @@
}
+void* File::MapExecutable(intptr_t* len) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
return read(handle_->fd(), buffer, num_bytes);
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 258b9a7..7783422 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -22,26 +22,47 @@
#include "include/dart_api.h"
+#include "platform/hashmap.h"
#include "platform/globals.h"
namespace dart {
namespace bin {
+// Exit code indicating an API error.
+static const int kApiErrorExitCode = 253;
+// Exit code indicating a compilation error.
+static const int kCompilationErrorExitCode = 254;
+// Exit code indicating an unhandled error that is not a compilation error.
+static const int kErrorExitCode = 255;
+// Exit code indicating a vm restart request. Never returned to the user.
+static const int kRestartRequestExitCode = 1000;
+
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
+ intptr_t exit_code = 0; \
Log::PrintErr("Error: %s", Dart_GetError(result)); \
+ if (Dart_IsCompilationError(result)) { \
+ exit_code = kCompilationErrorExitCode; \
+ } else if (Dart_IsApiError(result)) { \
+ exit_code = kApiErrorExitCode; \
+ } else if (Dart_IsVMRestartRequest(result)) { \
+ exit_code = kRestartRequestExitCode; \
+ } else { \
+ exit_code = kErrorExitCode; \
+ } \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
- exit(255); \
- } \
+ exit(exit_code); \
+ }
// Global state that indicates whether a snapshot is to be created and
// if so which file to write the snapshot into.
static const char* vm_isolate_snapshot_filename = NULL;
static const char* isolate_snapshot_filename = NULL;
-static const char* instructions_snapshot_filename = NULL;
-static const char* embedder_entry_points_manifest = NULL;
+static const char* assembly_filename = NULL;
+static const char* instructions_blob_filename = NULL;
+static const char* rodata_blob_filename = NULL;
static const char* package_root = NULL;
@@ -54,6 +75,10 @@
// Global state that captures the URL mappings specified on the command line.
static CommandLineOptions* url_mapping = NULL;
+// Global state that captures the entry point manifest files specified on the
+// command line.
+static CommandLineOptions* entry_points_files = NULL;
+
static bool IsValidFlag(const char* name,
const char* prefix,
intptr_t prefix_length) {
@@ -63,6 +88,93 @@
}
+// The environment provided through the command line using -D options.
+static dart::HashMap* environment = NULL;
+
+static void* GetHashmapKeyFromString(char* key) {
+ return reinterpret_cast<void*>(key);
+}
+
+static bool ProcessEnvironmentOption(const char* arg) {
+ ASSERT(arg != NULL);
+ if (*arg == '\0') {
+ return false;
+ }
+ if (*arg != '-') {
+ return false;
+ }
+ if (*(arg + 1) != 'D') {
+ return false;
+ }
+ arg = arg + 2;
+ if (*arg == '\0') {
+ return true;
+ }
+ if (environment == NULL) {
+ environment = new HashMap(&HashMap::SameStringValue, 4);
+ }
+ // Split the name=value part of the -Dname=value argument.
+ char* name;
+ char* value = NULL;
+ const char* equals_pos = strchr(arg, '=');
+ if (equals_pos == NULL) {
+ // No equal sign (name without value) currently not supported.
+ Log::PrintErr("No value given to -D option\n");
+ return false;
+ } else {
+ int name_len = equals_pos - arg;
+ if (name_len == 0) {
+ Log::PrintErr("No name given to -D option\n");
+ return false;
+ }
+ // Split name=value into name and value.
+ name = reinterpret_cast<char*>(malloc(name_len + 1));
+ strncpy(name, arg, name_len);
+ name[name_len] = '\0';
+ value = strdup(equals_pos + 1);
+ }
+ HashMap::Entry* entry = environment->Lookup(
+ GetHashmapKeyFromString(name), HashMap::StringHash(name), true);
+ ASSERT(entry != NULL); // Lookup adds an entry if key not found.
+ entry->value = value;
+ return true;
+}
+
+
+static Dart_Handle EnvironmentCallback(Dart_Handle name) {
+ uint8_t* utf8_array;
+ intptr_t utf8_len;
+ Dart_Handle result = Dart_Null();
+ Dart_Handle handle = Dart_StringToUTF8(name, &utf8_array, &utf8_len);
+ if (Dart_IsError(handle)) {
+ handle = Dart_ThrowException(
+ DartUtils::NewDartArgumentError(Dart_GetError(handle)));
+ } else {
+ char* name_chars = reinterpret_cast<char*>(malloc(utf8_len + 1));
+ memmove(name_chars, utf8_array, utf8_len);
+ name_chars[utf8_len] = '\0';
+ const char* value = NULL;
+ printf("Looking for %s\n", name_chars);
+ if (environment != NULL) {
+ HashMap::Entry* entry = environment->Lookup(
+ GetHashmapKeyFromString(name_chars),
+ HashMap::StringHash(name_chars),
+ false);
+ if (entry != NULL) {
+ value = reinterpret_cast<char*>(entry->value);
+ }
+ }
+ if (value != NULL) {
+ result = Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(value),
+ strlen(value));
+ }
+ free(name_chars);
+ }
+ return result;
+}
+
+
+
static const char* ProcessOption(const char* option, const char* name) {
const intptr_t length = strlen(name);
if (strncmp(option, name, length) == 0) {
@@ -92,10 +204,30 @@
}
-static bool ProcessInstructionsSnapshotOption(const char* option) {
- const char* name = ProcessOption(option, "--instructions_snapshot=");
+static bool ProcessAssemblyOption(const char* option) {
+ const char* name = ProcessOption(option, "--assembly=");
if (name != NULL) {
- instructions_snapshot_filename = name;
+ assembly_filename = name;
+ return true;
+ }
+ return false;
+}
+
+
+static bool ProcessInstructionsBlobOption(const char* option) {
+ const char* name = ProcessOption(option, "--instructions_blob=");
+ if (name != NULL) {
+ instructions_blob_filename = name;
+ return true;
+ }
+ return false;
+}
+
+
+static bool ProcessRodataBlobOption(const char* option) {
+ const char* name = ProcessOption(option, "--rodata_blob=");
+ if (name != NULL) {
+ rodata_blob_filename = name;
return true;
}
return false;
@@ -105,7 +237,7 @@
static bool ProcessEmbedderEntryPointsManifestOption(const char* option) {
const char* name = ProcessOption(option, "--embedder_entry_points_manifest=");
if (name != NULL) {
- embedder_entry_points_manifest = name;
+ entry_points_files->AddArgument(name);
return true;
}
return false;
@@ -114,6 +246,9 @@
static bool ProcessPackageRootOption(const char* option) {
const char* name = ProcessOption(option, "--package_root=");
+ if (name == NULL) {
+ name = ProcessOption(option, "--package-root=");
+ }
if (name != NULL) {
package_root = name;
return true;
@@ -135,13 +270,18 @@
}
+static bool IsSnapshottingForPrecompilation() {
+ return (assembly_filename != NULL) || (instructions_blob_filename != NULL);
+}
+
+
// Parse out the command line arguments. Returns -1 if the arguments
// are incorrect, 0 otherwise.
static int ParseArguments(int argc,
char** argv,
CommandLineOptions* vm_options,
char** script_name) {
- const char* kPrefix = "--";
+ const char* kPrefix = "-";
const intptr_t kPrefixLen = strlen(kPrefix);
// Skip the binary name.
@@ -151,10 +291,13 @@
while ((i < argc) && IsValidFlag(argv[i], kPrefix, kPrefixLen)) {
if (ProcessVmIsolateSnapshotOption(argv[i]) ||
ProcessIsolateSnapshotOption(argv[i]) ||
- ProcessInstructionsSnapshotOption(argv[i]) ||
+ ProcessAssemblyOption(argv[i]) ||
+ ProcessInstructionsBlobOption(argv[i]) ||
+ ProcessRodataBlobOption(argv[i]) ||
ProcessEmbedderEntryPointsManifestOption(argv[i]) ||
ProcessURLmappingOption(argv[i]) ||
- ProcessPackageRootOption(argv[i])) {
+ ProcessPackageRootOption(argv[i]) ||
+ ProcessEnvironmentOption(argv[i])) {
i += 1;
continue;
}
@@ -180,32 +323,36 @@
return -1;
}
- if ((instructions_snapshot_filename != NULL) &&
- (embedder_entry_points_manifest == NULL)) {
+ bool precompiled_as_assembly = assembly_filename != NULL;
+ bool precompiled_as_blobs = (instructions_blob_filename != NULL) ||
+ (rodata_blob_filename != NULL);
+ if (precompiled_as_assembly && precompiled_as_blobs) {
+ Log::PrintErr(
+ "Cannot request a precompiled snapshot simultaneously as "
+ "assembly (--assembly=<output.file>) and as blobs "
+ "(--instructions-blob=<output.file> and "
+ "--rodata-blob=<output.file>)\n\n");
+ return -1;
+ }
+ if ((instructions_blob_filename != NULL) != (rodata_blob_filename != NULL)) {
+ Log::PrintErr(
+ "Requesting a precompiled snapshot as blobs requires both "
+ "(--instructions-blob=<output.file> and "
+ "--rodata-blob=<output.file>)\n\n");
+ return -1;
+ }
+ if (IsSnapshottingForPrecompilation() &&
+ (entry_points_files->count() == 0)) {
Log::PrintErr(
"Specifying an instructions snapshot filename indicates precompilation"
". But no embedder entry points manifest was specified.\n\n");
return -1;
}
- if ((embedder_entry_points_manifest != NULL) &&
- (instructions_snapshot_filename == NULL)) {
- Log::PrintErr(
- "Specifying the embedder entry points manifest indicates "
- "precompilation. But no instuctions snapshot was specified.\n\n");
- return -1;
- }
-
return 0;
}
-static bool IsSnapshottingForPrecompilation(void) {
- return embedder_entry_points_manifest != NULL &&
- instructions_snapshot_filename != NULL;
-}
-
-
static void WriteSnapshotFile(const char* filename,
const uint8_t* buffer,
const intptr_t size) {
@@ -214,7 +361,7 @@
if (!file->WriteFully(buffer, size)) {
Log::PrintErr("Error: Failed to write snapshot file.\n\n");
}
- delete file;
+ file->Release();
}
@@ -469,17 +616,23 @@
" optional. \n"
" \n"
" Precompilation: \n"
-" In order to configure the snapshotter for precompilation, both the \n"
-" instructions snapshot and embedder entry points manifest must be \n"
-" specified. Assembly for the target architecture will be dumped into the \n"
-" instructions snapshot. This must be linked into the target binary in a \n"
-" separate step. The embedder entry points manifest lists the standalone \n"
-" entry points into the VM. Not specifying these will cause the tree shaker \n"
-" to disregard the same as being used. The format of this manifest is as \n"
-" follows. Each line in the manifest is a comma separated list of three \n"
-" elements. The first entry is the library URI, the second entry is the \n"
-" class name and the final entry the function name. The file must be \n"
-" terminated with a newline charater. \n"
+" In order to configure the snapshotter for precompilation, either \n"
+" --assembly=outputfile or --instructions_blob=outputfile1 and \n"
+" --rodata_blob=outputfile2 must be specified. If the former is choosen, \n"
+" assembly for the target architecture will be output into the given file, \n"
+" which must be compiled separately and either statically linked or \n"
+" dynamically loaded in the target executable. The symbols \n"
+" kInstructionsSnapshot and kDataSnapshot must be passed to Dart_Initialize.\n"
+" If the latter is choosen, binary data is output into the given files, \n"
+" which should be mmapped and passed to Dart_Initialize, with the \n"
+" instruction blob being mapped as executable. \n"
+" In both cases, a entry points manifest must be given to list the places \n"
+" in the Dart program the embedder calls from the C API (Dart_Invoke, etc). \n"
+" Not specifying these may cause the tree shaker to remove them from the \n"
+" program. The format of this manifest is as follows. Each line in the \n"
+" manifest is a comma separated list of three elements. The first entry is \n"
+" the library URI, the second entry is the class name and the final entry \n"
+" the function name. The file must be terminated with a newline charater. \n"
" \n"
" Example: \n"
" dart:something,SomeClass,doSomething \n"
@@ -497,12 +650,18 @@
" the command line to load the \n"
" libraries. \n"
" \n"
-" --instructions_snapshot=<file> (Precompilation only) Contains the \n"
+" --assembly=<file> (Precompilation only) Contains the \n"
" assembly that must be linked into \n"
" the target binary \n"
" \n"
-" --embedder_entry_points_manifest=<file> (Precompilation only) Contains \n"
-" the stanalone embedder entry points\n");
+" --instructions_blob=<file> (Precompilation only) Contains the \n"
+" --rodata_blob=<file> instructions and read-only data that \n"
+" must be mapped into the target binary \n"
+" \n"
+" --embedder_entry_points_manifest=<file> (Precompilation or app \n"
+" snapshots) Contains embedder's entry \n"
+" points into Dart code from the C API. \n"
+"\n");
}
@@ -510,9 +669,7 @@
if (Dart_IsError(library)) {
const char* err_msg = Dart_GetError(library);
Log::PrintErr("Errors encountered while loading: %s\n", err_msg);
- Dart_ExitScope();
- Dart_ShutdownIsolate();
- exit(255);
+ CHECK_RESULT(library);
}
ASSERT(Dart_IsLibrary(library));
}
@@ -781,31 +938,34 @@
}
-static Dart_QualifiedFunctionName* ParseEntryPointsManifestFile(
- const char* path) {
- if (path == NULL) {
- return NULL;
- }
+static Dart_QualifiedFunctionName* ParseEntryPointsManifestFiles() {
+ // Total number of entries across all manifest files.
+ int64_t entry_count = 0;
- FILE* file = fopen(path, "r");
-
- if (file == NULL) {
- Log::PrintErr("Could not open entry points manifest file\n");
- return NULL;
- }
-
- // Parse the file once but don't store the results. This is done to first
+ // Parse the files once but don't store the results. This is done to first
// determine the number of entries in the manifest
- int64_t entry_count = ParseEntryPointsManifestLines(file, NULL);
+ for (intptr_t i = 0; i < entry_points_files->count(); i++) {
+ const char* path = entry_points_files->GetArgument(i);
- if (entry_count <= 0) {
- Log::PrintErr(
- "Manifest file specified is invalid or contained no entries\n");
+ FILE* file = fopen(path, "r");
+
+ if (file == NULL) {
+ Log::PrintErr("Could not open entry points manifest file `%s`\n", path);
+ return NULL;
+ }
+
+ int64_t entries = ParseEntryPointsManifestLines(file, NULL);
fclose(file);
- return NULL;
- }
- rewind(file);
+ if (entries <= 0) {
+ Log::PrintErr(
+ "Manifest file `%s` specified is invalid or contained no entries\n",
+ path);
+ return NULL;
+ }
+
+ entry_count += entries;
+ }
// Allocate enough storage for the entries in the file plus a termination
// sentinel and parse it again to populate the allocation
@@ -813,10 +973,16 @@
reinterpret_cast<Dart_QualifiedFunctionName*>(
calloc(entry_count + 1, sizeof(Dart_QualifiedFunctionName)));
- int64_t parsed_entry_count = ParseEntryPointsManifestLines(file, entries);
- ASSERT(parsed_entry_count == entry_count);
+ int64_t parsed_entry_count = 0;
+ for (intptr_t i = 0; i < entry_points_files->count(); i++) {
+ const char* path = entry_points_files->GetArgument(i);
+ FILE* file = fopen(path, "r");
+ parsed_entry_count +=
+ ParseEntryPointsManifestLines(file, &entries[parsed_entry_count]);
+ fclose(file);
+ }
- fclose(file);
+ ASSERT(parsed_entry_count == entry_count);
// The entries allocation must be explicitly cleaned up via
// |CleanupEntryPointsCollection|
@@ -825,8 +991,7 @@
static Dart_QualifiedFunctionName* ParseEntryPointsManifestIfPresent() {
- Dart_QualifiedFunctionName* entries =
- ParseEntryPointsManifestFile(embedder_entry_points_manifest);
+ Dart_QualifiedFunctionName* entries = ParseEntryPointsManifestFiles();
if ((entries == NULL) && IsSnapshottingForPrecompilation()) {
Log::PrintErr(
"Could not find native embedder entry points during precompilation\n");
@@ -874,34 +1039,58 @@
intptr_t vm_isolate_size = 0;
uint8_t* isolate_buffer = NULL;
intptr_t isolate_size = 0;
- uint8_t* instructions_buffer = NULL;
- intptr_t instructions_size = 0;
+ uint8_t* assembly_buffer = NULL;
+ intptr_t assembly_size = 0;
+ uint8_t* instructions_blob_buffer = NULL;
+ intptr_t instructions_blob_size = 0;
+ uint8_t* rodata_blob_buffer = NULL;
+ intptr_t rodata_blob_size = 0;
// Precompile with specified embedder entry points
result = Dart_Precompile(standalone_entry_points, true);
CHECK_RESULT(result);
- // Create a precompiled snapshot. This gives us an instruction buffer with
- // machine code
- result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
- &vm_isolate_size,
- &isolate_buffer,
- &isolate_size,
- &instructions_buffer,
- &instructions_size);
- CHECK_RESULT(result);
+ // Create a precompiled snapshot.
+ bool as_assembly = assembly_filename != NULL;
+ if (as_assembly) {
+ result = Dart_CreatePrecompiledSnapshotAssembly(&vm_isolate_buffer,
+ &vm_isolate_size,
+ &isolate_buffer,
+ &isolate_size,
+ &assembly_buffer,
+ &assembly_size);
+ CHECK_RESULT(result);
+ } else {
+ result = Dart_CreatePrecompiledSnapshotBlob(&vm_isolate_buffer,
+ &vm_isolate_size,
+ &isolate_buffer,
+ &isolate_size,
+ &instructions_blob_buffer,
+ &instructions_blob_size,
+ &rodata_blob_buffer,
+ &rodata_blob_size);
+ CHECK_RESULT(result);
+ }
- // Now write the vm isolate, isolate and instructions snapshots out to the
- // specified files and exit.
+ // Now write the snapshot pieces out to the specified files and exit.
WriteSnapshotFile(vm_isolate_snapshot_filename,
vm_isolate_buffer,
vm_isolate_size);
WriteSnapshotFile(isolate_snapshot_filename,
isolate_buffer,
isolate_size);
- WriteSnapshotFile(instructions_snapshot_filename,
- instructions_buffer,
- instructions_size);
+ if (as_assembly) {
+ WriteSnapshotFile(assembly_filename,
+ assembly_buffer,
+ assembly_size);
+ } else {
+ WriteSnapshotFile(instructions_blob_filename,
+ instructions_blob_buffer,
+ instructions_blob_size);
+ WriteSnapshotFile(rodata_blob_filename,
+ rodata_blob_buffer,
+ rodata_blob_size);
+ }
Dart_ExitScope();
// Shutdown the isolate.
@@ -998,6 +1187,10 @@
CommandLineOptions url_mapping_array(argc);
url_mapping = &url_mapping_array;
+ // Initialize the entrypoints array.
+ CommandLineOptions entry_points_files_array(argc);
+ entry_points_files = &entry_points_files_array;
+
// Parse command line arguments.
if (ParseArguments(argc,
argv,
@@ -1067,6 +1260,9 @@
Dart_Handle library;
Dart_EnterScope();
+ result = Dart_SetEnvironmentCallback(EnvironmentCallback);
+ CHECK_RESULT(result);
+
ASSERT(vm_isolate_snapshot_filename != NULL);
ASSERT(isolate_snapshot_filename != NULL);
// Load up the script before a snapshot is created.
@@ -1108,6 +1304,8 @@
exit(255);
}
Dart_EnterScope();
+ result = Dart_SetEnvironmentCallback(EnvironmentCallback);
+ CHECK_RESULT(result);
// Set up the library tag handler in such a manner that it will use the
// URL mapping specified on the command line to load the libraries.
@@ -1129,8 +1327,7 @@
result = Dart_FinalizeLoading(false);
CHECK_RESULT(result);
- if (entry_points == NULL) {
- ASSERT(!IsSnapshottingForPrecompilation());
+ if (!IsSnapshottingForPrecompilation()) {
CreateAndWriteSnapshot();
} else {
CreateAndWritePrecompiledSnapshot(entry_points);
diff --git a/runtime/bin/io_impl_sources.gypi b/runtime/bin/io_impl_sources.gypi
index ccb050c..c0de4c23 100644
--- a/runtime/bin/io_impl_sources.gypi
+++ b/runtime/bin/io_impl_sources.gypi
@@ -46,12 +46,14 @@
'process_macos.cc',
'process_unsupported.cc',
'process_win.cc',
+ 'reference_counting.h',
'../../third_party/root_certificates/root_certificates.cc',
'root_certificates_unsupported.cc',
'secure_socket.h',
'secure_socket_boringssl.cc',
'secure_socket_boringssl.h',
'secure_socket_ios.cc',
+ 'secure_socket_ios.h',
'secure_socket_macos.cc',
'secure_socket_macos.h',
'secure_socket_unsupported.cc',
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 39946a7..4c55b6f 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -29,11 +29,14 @@
V(Directory_Delete, 2) \
V(Directory_Rename, 2) \
V(Directory_List, 3) \
+ V(Directory_GetAsyncDirectoryListerPointer, 1) \
+ V(Directory_SetAsyncDirectoryListerPointer, 2) \
V(EventHandler_SendData, 3) \
V(EventHandler_TimerMillisecondClock, 0) \
+ V(File_GetPointer, 1) \
+ V(File_SetPointer, 2) \
V(File_Open, 2) \
V(File_Exists, 1) \
- V(File_GetFD, 1) \
V(File_Close, 1) \
V(File_ReadByte, 1) \
V(File_WriteByte, 2) \
@@ -75,6 +78,7 @@
V(Filter_Processed, 3) \
V(InternetAddress_Parse, 1) \
V(IOService_NewServicePort, 0) \
+ V(NetworkInterface_ListSupported, 0) \
V(Platform_NumberOfProcessors, 0) \
V(Platform_OperatingSystem, 0) \
V(Platform_PathSeparator, 0) \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index fdf6248..0ef6653 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -83,6 +83,11 @@
static bool run_precompiled_snapshot = false;
+// Global flag that is used to indicate that we want to use blobs/mmap instead
+// of assembly/shared libraries for precompilation.
+static bool use_blobs = false;
+
+
// Value of the --gen/run_precompiled_snapshot flag.
// (This pointer points into an argv buffer and does not need to be
// free'd.)
@@ -105,7 +110,10 @@
extern const char* kPrecompiledDataSymbolName;
static const char* kPrecompiledVmIsolateName = "precompiled.vmisolate";
static const char* kPrecompiledIsolateName = "precompiled.isolate";
-static const char* kPrecompiledInstructionsName = "precompiled.S";
+static const char* kPrecompiledAssemblyName = "precompiled.S";
+static const char* kPrecompiledInstructionsBlobName =
+ "precompiled.instructions";
+static const char* kPrecompiledRodataBlobName = "precompiled.rodata";
static const char* kVMIsolateSuffix = "vmisolate";
static const char* kIsolateSuffix = "isolate";
@@ -326,6 +334,17 @@
}
+static bool ProcessUseBlobsOption(const char* arg,
+ CommandLineOptions* vm_options) {
+ ASSERT(arg != NULL);
+ if (*arg != '\0') {
+ return false;
+ }
+ use_blobs = true;
+ return true;
+}
+
+
static bool ProcessGenPrecompiledSnapshotOption(
const char* arg,
CommandLineOptions* vm_options) {
@@ -410,13 +429,13 @@
static bool ProcessRunFullSnapshotOption(
const char* filename, CommandLineOptions* vm_options) {
-#ifndef DART_PRODUCT_BINARY
+#if !defined(PRODUCT)
Log::PrintErr("Full Application snapshots can only be be run with"
- " dart_product\n");
+ " product mode\n");
return false;
#else
return ProcessSnapshotOptionHelper(filename, &run_full_snapshot);
-#endif // defined(DART_PRODUCT_BINARY)
+#endif // defined(PRODUCT)
}
@@ -513,6 +532,7 @@
// VM specific options to the standalone dart program.
{ "--compile_all", ProcessCompileAllOption },
+ { "--use_blobs", ProcessUseBlobsOption },
{ "--enable-vm-service", ProcessEnableVmServiceOption },
{ "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
{ "--observe", ProcessObserveOption },
@@ -746,14 +766,12 @@
int* exit_code) {
ASSERT(script_uri != NULL);
-#if defined(DART_PRODUCT_BINARY)
- const bool run_service_isolate = false;
-#elif defined(PRODUCT)
+#if defined(PRODUCT)
const bool run_service_isolate = !run_full_snapshot &&
!run_precompiled_snapshot;
#else
const bool run_service_isolate = !run_full_snapshot;
-#endif
+#endif // PRODUCT
if (!run_service_isolate &&
(strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0)) {
// We do not create a service isolate when running a full application
@@ -787,9 +805,6 @@
Dart_Handle result = Dart_SetLibraryTagHandler(DartUtils::LibraryTagHandler);
CHECK_RESULT(result);
-#if defined(DART_PRODUCT_BINARY)
- ASSERT(!Dart_IsServiceIsolate(isolate));
-#else
if (Dart_IsServiceIsolate(isolate)) {
// If this is the service isolate, load embedder specific bits and return.
if (!VmService::Setup(vm_service_server_ip,
@@ -806,7 +821,6 @@
Dart_ExitIsolate();
return isolate;
}
-#endif // defined(DART_PRODUCT_BINARY)
// Prepare builtin and other core libraries for use to resolve URIs.
// Set up various closures, e.g: printing, timers etc.
@@ -1105,7 +1119,7 @@
"Unable to open file %s for writing snapshot\n",
qualified_filename);
}
- delete file;
+ file->Release();
if (concat != NULL) {
delete concat;
}
@@ -1149,6 +1163,35 @@
}
+static void ReadExecutableSnapshotFile(const char* snapshot_directory,
+ const char* filename,
+ const uint8_t** buffer) {
+ char* concat = NULL;
+ const char* qualified_filename;
+ if ((snapshot_directory != NULL) && (strlen(snapshot_directory) > 0)) {
+ intptr_t len = snprintf(NULL, 0, "%s/%s", snapshot_directory, filename);
+ concat = new char[len + 1];
+ snprintf(concat, len + 1, "%s/%s", snapshot_directory, filename);
+ qualified_filename = concat;
+ } else {
+ qualified_filename = filename;
+ }
+
+ intptr_t len = -1;
+ *buffer = reinterpret_cast<uint8_t*>(
+ DartUtils::MapExecutable(qualified_filename, &len));
+ if ((*buffer == NULL) || (len == -1)) {
+ fprintf(stderr,
+ "Error: Unable to read snapshot file %s\n", qualified_filename);
+ fflush(stderr);
+ Platform::Exit(kErrorExitCode);
+ }
+ if (concat != NULL) {
+ delete concat;
+ }
+}
+
+
static void* LoadLibrarySymbol(const char* snapshot_directory,
const char* libname,
const char* symname) {
@@ -1307,7 +1350,7 @@
reinterpret_cast<IsolateData*>(Dart_IsolateData(isolate));
result = Dart_LibraryImportLibrary(
isolate_data->builtin_lib(), root_lib, Dart_Null());
-#if !defined(DART_PRODUCT_BINARY) && !defined(PRODUCT)
+#if !defined(PRODUCT)
if (is_noopt || gen_precompiled_snapshot) {
// Load the embedder's portion of the VM service's Dart code so it will
// be included in the precompiled snapshot.
@@ -1319,7 +1362,7 @@
exit(kErrorExitCode);
}
}
-#endif // !DART_PRODUCT_BINARY
+#endif // PRODUCT
if (compile_all) {
result = Dart_CompileAll();
@@ -1371,15 +1414,33 @@
intptr_t vm_isolate_size = 0;
uint8_t* isolate_buffer = NULL;
intptr_t isolate_size = 0;
- uint8_t* instructions_buffer = NULL;
- intptr_t instructions_size = 0;
- result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
- &vm_isolate_size,
- &isolate_buffer,
- &isolate_size,
- &instructions_buffer,
- &instructions_size);
- CHECK_RESULT(result);
+ uint8_t* assembly_buffer = NULL;
+ intptr_t assembly_size = 0;
+ uint8_t* instructions_blob_buffer = NULL;
+ intptr_t instructions_blob_size = NULL;
+ uint8_t* rodata_blob_buffer = NULL;
+ intptr_t rodata_blob_size = NULL;
+ if (use_blobs) {
+ result = Dart_CreatePrecompiledSnapshotBlob(
+ &vm_isolate_buffer,
+ &vm_isolate_size,
+ &isolate_buffer,
+ &isolate_size,
+ &instructions_blob_buffer,
+ &instructions_blob_size,
+ &rodata_blob_buffer,
+ &rodata_blob_size);
+ CHECK_RESULT(result);
+ } else {
+ result = Dart_CreatePrecompiledSnapshotAssembly(
+ &vm_isolate_buffer,
+ &vm_isolate_size,
+ &isolate_buffer,
+ &isolate_size,
+ &assembly_buffer,
+ &assembly_size);
+ CHECK_RESULT(result);
+ }
WriteSnapshotFile(precompiled_snapshot_directory,
kPrecompiledVmIsolateName,
false,
@@ -1390,11 +1451,24 @@
false,
isolate_buffer,
isolate_size);
- WriteSnapshotFile(precompiled_snapshot_directory,
- kPrecompiledInstructionsName,
- false,
- instructions_buffer,
- instructions_size);
+ if (use_blobs) {
+ WriteSnapshotFile(precompiled_snapshot_directory,
+ kPrecompiledInstructionsBlobName,
+ false,
+ instructions_blob_buffer,
+ instructions_blob_size);
+ WriteSnapshotFile(precompiled_snapshot_directory,
+ kPrecompiledRodataBlobName,
+ false,
+ rodata_blob_buffer,
+ rodata_blob_size);
+ } else {
+ WriteSnapshotFile(precompiled_snapshot_directory,
+ kPrecompiledAssemblyName,
+ false,
+ assembly_buffer,
+ assembly_size);
+ }
} else {
if (Dart_IsNull(root_lib)) {
ErrorExit(kErrorExitCode,
@@ -1611,21 +1685,29 @@
const uint8_t* instructions_snapshot = NULL;
const uint8_t* data_snapshot = NULL;
if (run_precompiled_snapshot) {
- instructions_snapshot = reinterpret_cast<const uint8_t*>(
- LoadLibrarySymbol(precompiled_snapshot_directory,
- kPrecompiledLibraryName,
- kPrecompiledInstructionsSymbolName));
- data_snapshot = reinterpret_cast<const uint8_t*>(
- LoadLibrarySymbol(precompiled_snapshot_directory,
- kPrecompiledLibraryName,
- kPrecompiledDataSymbolName));
ReadSnapshotFile(precompiled_snapshot_directory,
kPrecompiledVmIsolateName,
&vm_isolate_snapshot_buffer);
ReadSnapshotFile(precompiled_snapshot_directory,
kPrecompiledIsolateName,
&isolate_snapshot_buffer);
-
+ if (use_blobs) {
+ ReadExecutableSnapshotFile(precompiled_snapshot_directory,
+ kPrecompiledInstructionsBlobName,
+ &instructions_snapshot);
+ ReadSnapshotFile(precompiled_snapshot_directory,
+ kPrecompiledRodataBlobName,
+ &data_snapshot);
+ } else {
+ instructions_snapshot = reinterpret_cast<const uint8_t*>(
+ LoadLibrarySymbol(precompiled_snapshot_directory,
+ kPrecompiledLibraryName,
+ kPrecompiledInstructionsSymbolName));
+ data_snapshot = reinterpret_cast<const uint8_t*>(
+ LoadLibrarySymbol(precompiled_snapshot_directory,
+ kPrecompiledLibraryName,
+ kPrecompiledDataSymbolName));
+ }
} else if (run_full_snapshot) {
char* vm_snapshot_fname;
char* isolate_snapshot_fname;
diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h
index 79cb7be..b4c10a2 100644
--- a/runtime/bin/platform.h
+++ b/runtime/bin/platform.h
@@ -6,6 +6,7 @@
#define BIN_PLATFORM_H_
#include "bin/builtin.h"
+#include "platform/globals.h"
namespace dart {
namespace bin {
@@ -19,10 +20,30 @@
static int NumberOfProcessors();
// Returns a string representing the operating system ("linux",
- // "macos" or "windows"). The returned string should not be
+ // "macos", "windows", or "android"). The returned string should not be
// deallocated by the caller.
static const char* OperatingSystem();
+ // Returns the architecture name of the processor the VM is running on
+ // (ia32, x64, arm, arm64, or mips).
+ static const char* HostArchitecture() {
+#if defined(HOST_ARCH_ARM)
+ return "arm";
+#elif defined(HOST_ARCH_ARM64)
+ return "arm64";
+#elif defined(HOST_ARCH_IA32)
+ return "ia32";
+#elif defined(HOST_ARCH_MIPS)
+ return "mips";
+#elif defined(HOST_ARCH_X64)
+ return "x64";
+#else
+#error Architecture detection failed.
+#endif
+ }
+
+ static const char* LibraryPrefix();
+
// Returns a string representing the operating system's shared library
// extension (e.g. 'so', 'dll', ...). The returned string should not be
// deallocated by the caller.
diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc
index 1f29b21..f713c9a 100644
--- a/runtime/bin/platform_android.cc
+++ b/runtime/bin/platform_android.cc
@@ -47,6 +47,11 @@
}
+const char* Platform::LibraryPrefix() {
+ return "lib";
+}
+
+
const char* Platform::LibraryExtension() {
return "so";
}
diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc
index 054ff6d..4eb1a07 100644
--- a/runtime/bin/platform_linux.cc
+++ b/runtime/bin/platform_linux.cc
@@ -47,6 +47,11 @@
}
+const char* Platform::LibraryPrefix() {
+ return "lib";
+}
+
+
const char* Platform::LibraryExtension() {
return "so";
}
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 24c83fd..628056b 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -64,6 +64,11 @@
}
+const char* Platform::LibraryPrefix() {
+ return "lib";
+}
+
+
const char* Platform::LibraryExtension() {
return "dylib";
}
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index 1eb9d3b..ee1ac49 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -45,6 +45,11 @@
}
+const char* Platform::LibraryPrefix() {
+ return "";
+}
+
+
const char* Platform::LibraryExtension() {
return "dll";
}
diff --git a/runtime/bin/reference_counting.h b/runtime/bin/reference_counting.h
new file mode 100644
index 0000000..8e79f4f
--- /dev/null
+++ b/runtime/bin/reference_counting.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2016, 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 BIN_REFERENCE_COUNTING_H_
+#define BIN_REFERENCE_COUNTING_H_
+
+#include "vm/atomic.h"
+
+namespace dart {
+namespace bin {
+
+// Forward declaration.
+template <class Target> class RefCntReleaseScope;
+
+// Inherit from this class where instances of the derived class should be
+// reference counted. Reference counts on instances are incremented and
+// decremented explicitly with calls to Retain() and Release(). E.g.:
+//
+// class Foo : public ReferenceCounted<Foo> {
+// public:
+// Foo() : ReferenceCounted() {}
+// ...
+// };
+//
+// void DoStuffWithAFoo() {
+// Foo* foo = new Foo(); // Reference count starts at 1, so no explicit
+// // call to Retain is needed after allocation.
+// ...
+// foo->Release();
+// }
+template <class Derived>
+class ReferenceCounted {
+ public:
+ ReferenceCounted() :
+ ref_count_(1) {
+ }
+
+ ~ReferenceCounted() {
+ ASSERT(ref_count_ == 0);
+ }
+
+ void Retain() {
+ uintptr_t old = AtomicOperations::FetchAndIncrement(&ref_count_);
+ ASSERT(old > 0);
+ }
+
+ void Release() {
+ uintptr_t old = AtomicOperations::FetchAndDecrement(&ref_count_);
+ ASSERT(old > 0);
+ if (old == 1) {
+ delete static_cast<Derived*>(this);
+ }
+ }
+
+ private:
+ uintptr_t ref_count_;
+
+ // These are used only in the ASSERT below in RefCntReleaseScope.
+ uintptr_t ref_count() const { return ref_count_; }
+ friend class RefCntReleaseScope<Derived>;
+ DISALLOW_COPY_AND_ASSIGN(ReferenceCounted);
+};
+
+// Creates a scope at the end of which a reference counted object is
+// Released. This is useful for reference counted objects recieved by the IO
+// Service, which have already been Retained E.g.:
+//
+// CObject* Foo::FooRequest(const CObjectArray& request) {
+// Foo* foo = CObjectToFoo(request[0]);
+// RefCntReleaseScope<Foo> rs(foo);
+// ...
+// }
+template <class Target>
+class RefCntReleaseScope {
+ public:
+ explicit RefCntReleaseScope(ReferenceCounted<Target>* t) : target_(t) {
+ ASSERT(target_ != NULL);
+ ASSERT(target_->ref_count() > 0);
+ }
+ ~RefCntReleaseScope() {
+ target_->Release();
+ }
+
+ private:
+ ReferenceCounted<Target>* target_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(RefCntReleaseScope);
+};
+
+// Instances of RetainedPointer manage Retaining and Releasing reference counted
+// objects. There are two ways to use it. First, it can be used as a field in
+// a class, e.g.:
+//
+// class Foo {
+// private:
+// RetainedPointer<Bar> bar_;
+// public:
+// explicit Foo(Bar* b) : bar_(b) {}
+// }
+//
+// In this case, b will be Retained in Foo's constructor, and Released
+// automatically during Foo's destructor.
+//
+// RetainedPointer can also be used as a scope, as with RefCntReleaseScope,
+// with the difference that entering the scope also Retains the pointer, e.g.:
+//
+// void RetainAndDoStuffWithFoo(Foo* foo) {
+// RetainedPointer<Foo> retained(foo);
+// ..
+// }
+//
+// This Retains foo on entry and Releases foo at every exit from the scope.
+//
+// The underlying pointer can be accessed with the get() and set() methods.
+// Overwriting a non-NULL pointer with set causes that pointer to be Released.
+template <class Target>
+class RetainedPointer {
+ public:
+ RetainedPointer() : target_(NULL) {}
+
+ explicit RetainedPointer(ReferenceCounted<Target>* t) : target_(t) {
+ if (target_ != NULL) {
+ target_->Retain();
+ }
+ }
+
+ ~RetainedPointer() {
+ if (target_ != NULL) {
+ target_->Release();
+ }
+ }
+
+ void set(ReferenceCounted<Target>* t) {
+ if (target_ != NULL) {
+ target_->Release();
+ }
+ target_ = t;
+ if (target_ != NULL) {
+ target_->Retain();
+ }
+ }
+
+ Target* get() const {
+ return static_cast<Target*>(target_);
+ }
+
+ private:
+ ReferenceCounted<Target>* target_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(RetainedPointer);
+};
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_REFERENCE_COUNTING_H_
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index 07ff2b0..5dfee9e 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -15,7 +15,11 @@
defined(TARGET_OS_WINDOWS)
#include "bin/secure_socket_boringssl.h"
#elif defined(TARGET_OS_MACOS)
+#if TARGET_OS_IOS
+#include "bin/secure_socket_ios.h"
+#else // TARGET_OS_IOS
#include "bin/secure_socket_macos.h"
+#endif // TARGET_OS_IOS
#else
#error Unknown target os.
#endif
diff --git a/runtime/bin/secure_socket_boringssl.cc b/runtime/bin/secure_socket_boringssl.cc
index 530c21a..0fd1c9e 100644
--- a/runtime/bin/secure_socket_boringssl.cc
+++ b/runtime/bin/secure_socket_boringssl.cc
@@ -121,7 +121,7 @@
Dart_WeakPersistentHandle handle,
void* context_pointer) {
SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
- delete filter;
+ filter->Release();
}
@@ -207,7 +207,7 @@
SSLFilter* filter = new SSLFilter();
Dart_Handle err = SetFilter(args, filter);
if (Dart_IsError(err)) {
- delete filter;
+ filter->Release();
Dart_PropagateError(err);
}
err = filter->Init(dart_this);
@@ -324,7 +324,11 @@
void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
- intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
+ SSLFilter* filter = GetFilter(args);
+ // This filter pointer is passed to the IO Service thread. The IO Service
+ // thread must Release() the pointer when it is done with it.
+ filter->Retain();
+ intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
}
@@ -1086,6 +1090,8 @@
CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
CObjectIntptr filter_object(request[0]);
SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
+ RefCntReleaseScope<SSLFilter> rs(filter);
+
bool in_handshake = CObjectBool(request[1]).Value();
int starts[SSLFilter::kNumBuffers];
int ends[SSLFilter::kNumBuffers];
diff --git a/runtime/bin/secure_socket_boringssl.h b/runtime/bin/secure_socket_boringssl.h
index 9dbe250..d5449a4 100644
--- a/runtime/bin/secure_socket_boringssl.h
+++ b/runtime/bin/secure_socket_boringssl.h
@@ -21,6 +21,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/reference_counting.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
@@ -39,7 +40,7 @@
* reading and writing encrypted text. The filter handles handshaking
* and certificate verification.
*/
-class SSLFilter {
+class SSLFilter : public ReferenceCounted<SSLFilter> {
public:
// These enums must agree with those in sdk/lib/io/secure_socket.dart.
enum BufferIndex {
diff --git a/runtime/bin/secure_socket_ios.cc b/runtime/bin/secure_socket_ios.cc
index 76da230..a92c45b 100644
--- a/runtime/bin/secure_socket_ios.cc
+++ b/runtime/bin/secure_socket_ios.cc
@@ -8,7 +8,7 @@
#if TARGET_OS_IOS
#include "bin/secure_socket.h"
-#include "bin/secure_socket_macos.h"
+#include "bin/secure_socket_ios.h"
#include <errno.h>
#include <fcntl.h>
@@ -52,58 +52,21 @@
static const bool SSL_LOG_STATUS = false;
static const bool SSL_LOG_DATA = false;
+static const bool SSL_LOG_CERTS = false;
static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
+static const intptr_t PEM_BUFSIZE = 1024;
-// SSLCertContext wraps the certificates needed for a SecureTransport
-// connection. Fields are protected by the mutex_ field, and may only be set
-// once. This is to allow access by both the Dart thread and the IOService
-// thread. Setters return false if the field was already set.
-class SSLCertContext {
- public:
- SSLCertContext() :
- mutex_(new Mutex()),
- trusted_certs_(NULL),
- trust_builtin_(false) {}
+static char* CFStringRefToCString(CFStringRef cfstring) {
+ CFIndex len = CFStringGetLength(cfstring);
+ CFIndex max_len =
+ CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
+ char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
+ ASSERT(result != NULL);
+ bool success =
+ CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8);
+ return success ? result : NULL;
+}
- ~SSLCertContext() {
- delete mutex_;
- if (trusted_certs_ != NULL) {
- CFRelease(trusted_certs_);
- }
- }
-
- CFMutableArrayRef trusted_certs() {
- MutexLocker m(mutex_);
- return trusted_certs_;
- }
- void add_trusted_cert(SecCertificateRef trusted_cert) {
- // Takes ownership of trusted_cert.
- MutexLocker m(mutex_);
- if (trusted_certs_ == NULL) {
- trusted_certs_ = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- }
- CFArrayAppendValue(trusted_certs_, trusted_cert);
- CFRelease(trusted_cert); // trusted_cert is retained by the array.
- }
-
- bool trust_builtin() {
- MutexLocker m(mutex_);
- return trust_builtin_;
- }
- void set_trust_builtin(bool trust_builtin) {
- MutexLocker m(mutex_);
- trust_builtin_ = trust_builtin;
- }
-
- private:
- // The context is accessed both by Dart code and the IOService. This mutex
- // protects all fields.
- Mutex* mutex_;
- CFMutableArrayRef trusted_certs_;
- bool trust_builtin_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
-};
// Handle an error reported from the SecureTransport library.
static void ThrowIOException(OSStatus status,
@@ -148,7 +111,7 @@
Dart_WeakPersistentHandle handle,
void* context_pointer) {
SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
- delete filter;
+ filter->Release();
}
@@ -187,7 +150,7 @@
Dart_WeakPersistentHandle handle,
void* context_pointer) {
SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
- delete context;
+ context->Release();
}
@@ -210,6 +173,18 @@
}
+static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
+ SecCertificateRef certificate;
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_GetNativeInstanceField(
+ dart_this,
+ kX509NativeFieldIndex,
+ reinterpret_cast<intptr_t*>(&certificate)));
+ return certificate;
+}
+
+
static void ReleaseCertificate(void* isolate_data,
Dart_WeakPersistentHandle handle,
void* context_pointer) {
@@ -256,12 +231,161 @@
}
+static const char* GetPasswordArgument(Dart_NativeArguments args,
+ intptr_t index) {
+ Dart_Handle password_object =
+ ThrowIfError(Dart_GetNativeArgument(args, index));
+ const char* password = NULL;
+ if (Dart_IsString(password_object)) {
+ ThrowIfError(Dart_StringToCString(password_object, &password));
+ if (strlen(password) > PEM_BUFSIZE - 1) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Password length is greater than 1023 bytes."));
+ }
+ } else if (Dart_IsNull(password_object)) {
+ password = "";
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Password is not a String or null"));
+ }
+ return password;
+}
+
+
+static OSStatus TryPKCS12Import(CFDataRef cfdata,
+ CFStringRef password,
+ CFArrayRef* out_certs,
+ SecIdentityRef* out_identity) {
+ const void* keys[] = { kSecImportExportPassphrase };
+ const void* values[] = { password };
+ CFDictionaryRef params =
+ CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
+ CFArrayRef items = NULL;
+ OSStatus status = SecPKCS12Import(cfdata, params, &items);
+ CFRelease(params);
+
+ if (status != noErr) {
+ if (SSL_LOG_STATUS) {
+ Log::PrintErr("SecPKCS12Import: status = %ld",
+ static_cast<intptr_t>(status));
+ return status;
+ }
+ }
+
+ CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
+ if (SSL_LOG_CERTS) {
+ Log::PrintErr("TryPKCS12Import succeeded, count = %ld\n", items_length);
+ }
+
+ // Empty list indicates a decoding failure of some sort.
+ if ((items != NULL) && (items_length == 0)) {
+ CFRelease(items);
+ return errSSLBadCert;
+ }
+
+ CFMutableArrayRef result_certs =
+ CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ SecIdentityRef result_identity = NULL;
+
+ for (CFIndex i = 0; i < items_length; i++) {
+ CFTypeRef item =
+ reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i));
+ ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
+ CFDictionaryRef dict = reinterpret_cast<CFDictionaryRef>(item);
+
+ // Trust.
+ CFTypeRef trust_item = CFDictionaryGetValue(dict, kSecImportItemTrust);
+ if (trust_item != NULL) {
+ ASSERT(CFGetTypeID(trust_item) == SecTrustGetTypeID());
+ if (SSL_LOG_CERTS) {
+ Log::PrintErr("\titem %ld has a trust object\n", i);
+ }
+ // TODO(zra): Is this useful for anything?
+ }
+
+ // Identity.
+ CFTypeRef identity_item =
+ CFDictionaryGetValue(dict, kSecImportItemIdentity);
+ if (identity_item != NULL) {
+ ASSERT(CFGetTypeID(identity_item) == SecIdentityGetTypeID());
+ if (SSL_LOG_CERTS) {
+ Log::PrintErr("\titem %ld has an identity object\n", i);
+ }
+ // Only extract the first identity we find.
+ if (result_identity == NULL) {
+ result_identity =
+ reinterpret_cast<SecIdentityRef>(const_cast<void*>(identity_item));
+ CFRetain(result_identity);
+ }
+ }
+
+ // Certificates.
+ CFTypeRef cert_items = CFDictionaryGetValue(dict, kSecImportItemCertChain);
+ if (cert_items != NULL) {
+ ASSERT(CFGetTypeID(cert_items) == CFArrayGetTypeID());
+ CFArrayRef certs = reinterpret_cast<CFArrayRef>(cert_items);
+ if (SSL_LOG_CERTS) {
+ CFIndex count = CFArrayGetCount(certs);
+ Log::PrintErr("\titem %ld has a cert chain %ld certs long\n", i, count);
+ }
+ CFArrayAppendArray(
+ result_certs, certs, CFRangeMake(0, CFArrayGetCount(certs)));
+ }
+ }
+
+ if (out_certs == NULL) {
+ if (result_certs != NULL) {
+ CFRelease(result_certs);
+ }
+ } else {
+ *out_certs = result_certs;
+ }
+
+ if (out_identity == NULL) {
+ if (result_identity != NULL) {
+ CFRelease(result_identity);
+ }
+ } else {
+ *out_identity = result_identity;
+ }
+
+ // On failure, don't return any objects.
+ ASSERT((status == noErr) ||
+ ((result_certs == NULL) && (result_identity == NULL)));
+ return status;
+}
+
+
+static OSStatus ExtractSecItems(uint8_t* buffer,
+ intptr_t length,
+ const char* password,
+ CFArrayRef* out_certs,
+ SecIdentityRef* out_identity) {
+ ASSERT(buffer != NULL);
+ ASSERT(password != NULL);
+ OSStatus status = noErr;
+
+ CFDataRef cfdata = CFDataCreateWithBytesNoCopy(
+ NULL, buffer, length, kCFAllocatorNull);
+ CFStringRef cfpassword = CFStringCreateWithCStringNoCopy(
+ NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull);
+ ASSERT(cfdata != NULL);
+ ASSERT(cfpassword != NULL);
+
+ status = TryPKCS12Import(cfdata, cfpassword, out_certs, out_identity);
+
+ CFRelease(cfdata);
+ CFRelease(cfpassword);
+ return status;
+}
+
+
void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
Dart_Handle err = SetFilter(args, filter);
if (Dart_IsError(err)) {
- delete filter;
+ filter->Release();
Dart_PropagateError(err);
}
err = filter->Init(dart_this);
@@ -372,7 +496,11 @@
void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
- intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
+ SSLFilter* filter = GetFilter(args);
+ // This filter pointer is passed to the IO Service thread. The IO Service
+ // thread must Release() the pointer when it is done with it.
+ filter->Retain();
+ intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
}
@@ -382,7 +510,7 @@
// cert_context deleted in DeleteCertContext finalizer.
Dart_Handle err = SetSecurityContext(args, cert_context);
if (Dart_IsError(err)) {
- delete cert_context;
+ cert_context->Release();
Dart_PropagateError(err);
}
}
@@ -390,8 +518,42 @@
void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
Dart_NativeArguments args) {
- Dart_ThrowException(DartUtils::NewDartUnsupportedError(
- "SecurityContext.usePrivateKeyBytes is not yet implemented."));
+ SSLCertContext* context = GetSecurityContext(args);
+ const char* password = GetPasswordArgument(args, 2);
+
+ OSStatus status;
+ CFArrayRef cert_chain = NULL;
+ SecIdentityRef identity = NULL;
+ {
+ ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ status = ExtractSecItems(
+ buffer.get(), buffer.length(), password, &cert_chain, &identity);
+ }
+
+ // Set the context fields. Repeated calls to usePrivateKeyBytes are an error.
+ bool set_failure = false;
+ if ((identity != NULL) && !context->set_identity(identity)) {
+ CFRelease(identity);
+ if (cert_chain != NULL) {
+ CFRelease(cert_chain);
+ }
+ set_failure = true;
+ }
+
+ // We can't have set a cert_chain without also having set an identity.
+ // That is, if context->set_identity() succeeds, then it is impossible for
+ // context->set_cert_chain() to fail. This is because SecPKCS12Import never
+ // returns a cert chain without also returning a private key.
+ ASSERT(set_failure || (context->cert_chain() == NULL));
+ if (!set_failure && (cert_chain != NULL)) {
+ context->set_cert_chain(cert_chain);
+ }
+
+ if (set_failure) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "usePrivateKeyBytes has already been called on the given context."));
+ }
+ CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
}
@@ -433,15 +595,16 @@
void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
Dart_NativeArguments args) {
- Dart_ThrowException(DartUtils::NewDartUnsupportedError(
- "SecurityContext.useCertificateChainBytes is not yet implemented."));
+ // This is a no-op on iOS. We get the cert chain along with the private key
+ // in UsePrivateyKeyBytes().
}
void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
Dart_NativeArguments args) {
Dart_ThrowException(DartUtils::NewDartUnsupportedError(
- "SecurityContext.setClientAuthoritiesBytes is not yet implemented."));
+ "SecurityContext.setClientAuthoritiesBytes is not supported on this "
+ "platform."));
}
@@ -453,8 +616,16 @@
void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
- Dart_ThrowException(DartUtils::NewDartUnsupportedError(
- "X509Certificate.subject is not yet implemented."));
+ SecCertificateRef certificate = GetX509Certificate(args);
+ CFStringRef cfsubject = SecCertificateCopySubjectSummary(certificate);
+ if (cfsubject != NULL) {
+ char* csubject = CFStringRefToCString(cfsubject);
+ CFRelease(cfsubject);
+ Dart_SetReturnValue(args, Dart_NewStringFromCString(csubject));
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "X509.subject failed to find subject's common name."));
+ }
}
@@ -498,6 +669,8 @@
CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
CObjectIntptr filter_object(request[0]);
SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
+ RefCntReleaseScope<SSLFilter> rs(filter);
+
bool in_handshake = CObjectBool(request[1]).Value();
intptr_t starts[SSLFilter::kNumBuffers];
intptr_t ends[SSLFilter::kNumBuffers];
@@ -864,6 +1037,27 @@
"TlsException",
"Failed to set minimum protocol version to kTLSProtocol1");
+ // If the context has an identity pass it to SSLSetCertificate().
+ if (context->identity() != NULL) {
+ CFMutableArrayRef chain =
+ CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(chain, context->identity());
+
+ // Append the certificate chain if there is one.
+ if (context->cert_chain() != NULL) {
+ // Skip the first one, it's already included in the identity.
+ CFIndex chain_length = CFArrayGetCount(context->cert_chain());
+ if (chain_length > 1) {
+ CFArrayAppendArray(
+ chain, context->cert_chain(), CFRangeMake(1, chain_length));
+ }
+ }
+
+ status = SSLSetCertificate(ssl_context, chain);
+ CFRelease(chain);
+ CheckStatus(status, "TlsException", "SSLSetCertificate failed");
+ }
+
if (is_server) {
SSLAuthenticate auth =
require_client_certificate
@@ -886,7 +1080,7 @@
}
// Add the contexts to our wrapper.
- cert_context_ = context;
+ cert_context_.set(context);
ssl_context_ = ssl_context;
is_server_ = is_server;
@@ -908,7 +1102,7 @@
OSStatus status = noErr;
if (SSL_LOG_STATUS) {
- Log::Print("Handshake evaluating trust.\n");
+ Log::PrintErr("Handshake evaluating trust.\n");
}
SecTrustRef peer_trust = NULL;
status = SSLCopyPeerTrust(ssl_context_, &peer_trust);
@@ -918,15 +1112,16 @@
return noErr;
}
if (SSL_LOG_STATUS) {
- Log::Print("Handshake error from SSLCopyPeerTrust(): %ld.\n",
+ Log::PrintErr("Handshake error from SSLCopyPeerTrust(): %ld.\n",
static_cast<intptr_t>(status));
}
return status;
}
CFArrayRef trusted_certs = NULL;
- if (cert_context_->trusted_certs() != NULL) {
- trusted_certs = CFArrayCreateCopy(NULL, cert_context_->trusted_certs());
+ if (cert_context_.get()->trusted_certs() != NULL) {
+ trusted_certs =
+ CFArrayCreateCopy(NULL, cert_context_.get()->trusted_certs());
} else {
trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
}
@@ -934,7 +1129,7 @@
status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
if (status != noErr) {
if (SSL_LOG_STATUS) {
- Log::Print("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
+ Log::PrintErr("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
static_cast<intptr_t>(status));
}
CFRelease(trusted_certs);
@@ -943,12 +1138,12 @@
}
if (SSL_LOG_STATUS) {
- Log::Print("Handshake %s built in root certs\n",
- cert_context_->trust_builtin() ? "trusting" : "not trusting");
+ Log::PrintErr("Handshake %s built in root certs\n",
+ cert_context_.get()->trust_builtin() ? "trusting" : "not trusting");
}
status = SecTrustSetAnchorCertificatesOnly(
- peer_trust, !cert_context_->trust_builtin());
+ peer_trust, !cert_context_.get()->trust_builtin());
if (status != noErr) {
CFRelease(trusted_certs);
CFRelease(peer_trust);
@@ -982,7 +1177,7 @@
return noErr;
} else {
if (SSL_LOG_STATUS) {
- Log::Print("Trust eval failed: trust_restul = %d\n", trust_result);
+ Log::PrintErr("Trust eval failed: trust_result = %d\n", trust_result);
}
bad_cert_ = true;
return errSSLBadCert;
@@ -991,15 +1186,15 @@
OSStatus SSLFilter::Handshake() {
- ASSERT(cert_context_ != NULL);
+ ASSERT(cert_context_.get() != NULL);
ASSERT(ssl_context_ != NULL);
// Try and push handshake along.
if (SSL_LOG_STATUS) {
- Log::Print("Doing SSLHandshake\n");
+ Log::PrintErr("Doing SSLHandshake\n");
}
OSStatus status = SSLHandshake(ssl_context_);
if (SSL_LOG_STATUS) {
- Log::Print("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
+ Log::PrintErr("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
}
if ((status == errSSLServerAuthCompleted) ||
@@ -1024,7 +1219,7 @@
// Handshake succeeded.
if ((in_handshake_) && (status == noErr)) {
if (SSL_LOG_STATUS) {
- Log::Print("Finished with the Handshake\n");
+ Log::PrintErr("Finished with the Handshake\n");
}
connected_ = true;
}
@@ -1058,7 +1253,7 @@
OSStatus SSLFilter::CheckHandshake() {
if (bad_cert_ && in_handshake_) {
if (SSL_LOG_STATUS) {
- Log::Print("Invoking bad certificate callback\n");
+ Log::PrintErr("Invoking bad certificate callback\n");
}
ASSERT(peer_certs_ != NULL);
CFIndex peer_certs_len = CFArrayGetCount(peer_certs_);
@@ -1081,7 +1276,7 @@
if (connected_ && in_handshake_) {
if (SSL_LOG_STATUS) {
- Log::Print("Invoking handshake complete callback\n");
+ Log::PrintErr("Invoking handshake complete callback\n");
}
ThrowIfError(Dart_InvokeClosure(
Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
@@ -1104,8 +1299,6 @@
SSLFilter::~SSLFilter() {
- // cert_context_ deleted by finalizer. Don't delete here.
- cert_context_ = NULL;
if (ssl_context_ != NULL) {
CFRelease(ssl_context_);
ssl_context_ = NULL;
@@ -1202,7 +1395,7 @@
}
if (SSL_LOG_DATA) {
- Log::Print("SSLReadCallback: requested: %ld, read %ld bytes\n",
+ Log::PrintErr("SSLReadCallback: requested: %ld, read %ld bytes\n",
*data_requested, data_read);
}
@@ -1228,7 +1421,7 @@
length,
&bytes);
if (SSL_LOG_STATUS) {
- Log::Print("SSLRead: status = %ld\n", static_cast<intptr_t>(status));
+ Log::PrintErr("SSLRead: status = %ld\n", static_cast<intptr_t>(status));
}
if ((status != noErr) && (status != errSSLWouldBlock)) {
*bytes_processed = 0;
@@ -1236,7 +1429,8 @@
}
}
if (SSL_LOG_DATA) {
- Log::Print("ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n",
+ Log::PrintErr(
+ "ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n",
length, bytes);
}
*bytes_processed = static_cast<intptr_t>(bytes);
@@ -1293,7 +1487,7 @@
}
if (SSL_LOG_DATA) {
- Log::Print("SSLWriteCallback: provided: %ld, written %ld bytes\n",
+ Log::PrintErr("SSLWriteCallback: provided: %ld, written %ld bytes\n",
*data_provided, data_written);
}
@@ -1317,7 +1511,7 @@
length,
&bytes);
if (SSL_LOG_STATUS) {
- Log::Print("SSLWrite: status = %ld\n", static_cast<intptr_t>(status));
+ Log::PrintErr("SSLWrite: status = %ld\n", static_cast<intptr_t>(status));
}
if ((status != noErr) && (status != errSSLWouldBlock)) {
*bytes_processed = 0;
@@ -1325,7 +1519,7 @@
}
}
if (SSL_LOG_DATA) {
- Log::Print("ProcessWritePlaintextBuffer: requested: %ld, written: %ld\n",
+ Log::PrintErr("ProcessWritePlaintextBuffer: requested: %ld, written: %ld\n",
length, bytes);
}
*bytes_processed = static_cast<intptr_t>(bytes);
diff --git a/runtime/bin/secure_socket_ios.h b/runtime/bin/secure_socket_ios.h
new file mode 100644
index 0000000..d67de71
--- /dev/null
+++ b/runtime/bin/secure_socket_ios.h
@@ -0,0 +1,240 @@
+// Copyright (c) 2016, 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 BIN_SECURE_SOCKET_IOS_H_
+#define BIN_SECURE_SOCKET_IOS_H_
+
+#if !defined(BIN_SECURE_SOCKET_H_)
+#error Do not include secure_socket_macos.h directly. Use secure_socket.h.
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/SecureTransport.h>
+#include <Security/Security.h>
+
+#include "bin/builtin.h"
+#include "bin/dartutils.h"
+#include "bin/lockers.h"
+#include "bin/reference_counting.h"
+#include "bin/socket.h"
+#include "bin/thread.h"
+#include "bin/utils.h"
+
+namespace dart {
+namespace bin {
+
+// SSLCertContext wraps the certificates needed for a SecureTransport
+// connection. Fields are protected by the mutex_ field, and may only be set
+// once. This is to allow access by both the Dart thread and the IOService
+// thread. Setters return false if the field was already set.
+class SSLCertContext : public ReferenceCounted<SSLCertContext> {
+ public:
+ SSLCertContext() :
+ ReferenceCounted(),
+ mutex_(new Mutex()),
+ trusted_certs_(NULL),
+ identity_(NULL),
+ cert_chain_(NULL),
+ trust_builtin_(false) {}
+
+ ~SSLCertContext() {
+ {
+ MutexLocker m(mutex_);
+ if (trusted_certs_ != NULL) {
+ CFRelease(trusted_certs_);
+ }
+ if (identity_ != NULL) {
+ CFRelease(identity_);
+ }
+ if (cert_chain_ != NULL) {
+ CFRelease(cert_chain_);
+ }
+ }
+ delete mutex_;
+ }
+
+ CFMutableArrayRef trusted_certs() {
+ MutexLocker m(mutex_);
+ return trusted_certs_;
+ }
+ void add_trusted_cert(SecCertificateRef trusted_cert) {
+ // Takes ownership of trusted_cert.
+ MutexLocker m(mutex_);
+ if (trusted_certs_ == NULL) {
+ trusted_certs_ = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(trusted_certs_, trusted_cert);
+ CFRelease(trusted_cert); // trusted_cert is retained by the array.
+ }
+
+ SecIdentityRef identity() {
+ MutexLocker m(mutex_);
+ return identity_;
+ }
+ bool set_identity(SecIdentityRef identity) {
+ MutexLocker m(mutex_);
+ if (identity_ == NULL) {
+ identity_ = identity;
+ return true;
+ }
+ return false;
+ }
+
+ CFArrayRef cert_chain() {
+ MutexLocker m(mutex_);
+ return cert_chain_;
+ }
+ bool set_cert_chain(CFArrayRef cert_chain) {
+ MutexLocker m(mutex_);
+ if (cert_chain_ == NULL) {
+ cert_chain_ = cert_chain;
+ return true;
+ }
+ return false;
+ }
+
+ bool trust_builtin() {
+ MutexLocker m(mutex_);
+ return trust_builtin_;
+ }
+ void set_trust_builtin(bool trust_builtin) {
+ MutexLocker m(mutex_);
+ trust_builtin_ = trust_builtin;
+ }
+
+ private:
+ // The context is accessed both by Dart code and the IOService. This mutex
+ // protects all fields.
+ Mutex* mutex_;
+ CFMutableArrayRef trusted_certs_;
+ SecIdentityRef identity_;
+ CFArrayRef cert_chain_;
+ bool trust_builtin_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
+};
+
+// SSLFilter encapsulates the SecureTransport code in a filter that communicates
+// with the containing _SecureFilterImpl Dart object through four shared
+// ExternalByteArray buffers, for reading and writing plaintext, and
+// reading and writing encrypted text. The filter handles handshaking
+// and certificate verification.
+class SSLFilter : public ReferenceCounted<SSLFilter> {
+ public:
+ // These enums must agree with those in sdk/lib/io/secure_socket.dart.
+ enum BufferIndex {
+ kReadPlaintext,
+ kWritePlaintext,
+ kReadEncrypted,
+ kWriteEncrypted,
+ kNumBuffers,
+ kFirstEncrypted = kReadEncrypted
+ };
+
+ SSLFilter()
+ : ReferenceCounted(),
+ cert_context_(NULL),
+ ssl_context_(NULL),
+ peer_certs_(NULL),
+ string_start_(NULL),
+ string_length_(NULL),
+ handshake_complete_(NULL),
+ bad_certificate_callback_(NULL),
+ in_handshake_(false),
+ connected_(false),
+ bad_cert_(false),
+ is_server_(false),
+ hostname_(NULL) {
+ }
+
+ ~SSLFilter();
+
+ // Callback called by the IOService.
+ static CObject* ProcessFilterRequest(const CObjectArray& request);
+
+ Dart_Handle Init(Dart_Handle dart_this);
+ void Connect(Dart_Handle dart_this,
+ const char* hostname,
+ SSLCertContext* context,
+ bool is_server,
+ bool request_client_certificate,
+ bool require_client_certificate);
+ void Destroy();
+ OSStatus CheckHandshake();
+ void Renegotiate(bool use_session_cache,
+ bool request_client_certificate,
+ bool require_client_certificate);
+ void RegisterHandshakeCompleteCallback(Dart_Handle handshake_complete);
+ void RegisterBadCertificateCallback(Dart_Handle callback);
+ Dart_Handle PeerCertificate();
+
+ private:
+ static OSStatus SSLReadCallback(SSLConnectionRef connection,
+ void* data,
+ size_t* data_length);
+ static OSStatus SSLWriteCallback(SSLConnectionRef connection,
+ const void* data,
+ size_t* data_length);
+
+ static bool isBufferEncrypted(intptr_t i) {
+ return static_cast<BufferIndex>(i) >= kFirstEncrypted;
+ }
+ Dart_Handle InitializeBuffers(Dart_Handle dart_this);
+
+ intptr_t GetBufferStart(intptr_t idx) const;
+ intptr_t GetBufferEnd(intptr_t idx) const;
+ void SetBufferStart(intptr_t idx, intptr_t value);
+ void SetBufferEnd(intptr_t idx, intptr_t value);
+
+ OSStatus ProcessAllBuffers(intptr_t starts[kNumBuffers],
+ intptr_t ends[kNumBuffers],
+ bool in_handshake);
+ OSStatus ProcessReadPlaintextBuffer(intptr_t start,
+ intptr_t end,
+ intptr_t* bytes_processed);
+ OSStatus ProcessWritePlaintextBuffer(intptr_t start,
+ intptr_t end,
+ intptr_t* bytes_processed);
+
+ // These calls can block on IO, and should only be invoked from
+ // from ProcessAllBuffers from ProcessFilterRequest.
+ OSStatus EvaluatePeerTrust();
+ OSStatus Handshake();
+ Dart_Handle InvokeBadCertCallback(SecCertificateRef peer_cert);
+
+ RetainedPointer<SSLCertContext> cert_context_;
+ SSLContextRef ssl_context_;
+ CFArrayRef peer_certs_;
+
+ // starts and ends filled in at the start of ProcessAllBuffers.
+ // If these are NULL, then try to get the pointers out of
+ // dart_buffer_objects_.
+ uint8_t* buffers_[kNumBuffers];
+ intptr_t* buffer_starts_[kNumBuffers];
+ intptr_t* buffer_ends_[kNumBuffers];
+ intptr_t buffer_size_;
+ intptr_t encrypted_buffer_size_;
+ Dart_PersistentHandle string_start_;
+ Dart_PersistentHandle string_length_;
+ Dart_PersistentHandle dart_buffer_objects_[kNumBuffers];
+ Dart_PersistentHandle handshake_complete_;
+ Dart_PersistentHandle bad_certificate_callback_;
+ bool in_handshake_;
+ bool connected_;
+ bool bad_cert_;
+ bool is_server_;
+ char* hostname_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLFilter);
+};
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_SECURE_SOCKET_IOS_H_
diff --git a/runtime/bin/secure_socket_macos.cc b/runtime/bin/secure_socket_macos.cc
index 84b10c0..6b564df 100644
--- a/runtime/bin/secure_socket_macos.cc
+++ b/runtime/bin/secure_socket_macos.cc
@@ -66,134 +66,6 @@
static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
static const intptr_t PEM_BUFSIZE = 1024;
-// SSLCertContext wraps the certificates needed for a SecureTransport
-// connection. Fields are protected by the mutex_ field, and may only be set
-// once. This is to allow access by both the Dart thread and the IOService
-// thread. Setters return false if the field was already set.
-class SSLCertContext {
- public:
- SSLCertContext() :
- mutex_(new Mutex()),
- private_key_(NULL),
- keychain_(NULL),
- cert_chain_(NULL),
- trusted_certs_(NULL),
- cert_authorities_(NULL),
- trust_builtin_(false) {}
-
- ~SSLCertContext() {
- if (private_key_ != NULL) {
- CFRelease(private_key_);
- }
- if (keychain_ != NULL) {
- SecKeychainDelete(keychain_);
- CFRelease(keychain_);
- }
- if (cert_chain_ != NULL) {
- CFRelease(cert_chain_);
- }
- if (trusted_certs_ != NULL) {
- CFRelease(trusted_certs_);
- }
- if (cert_authorities_ != NULL) {
- CFRelease(cert_authorities_);
- }
- delete mutex_;
- }
-
- SecKeyRef private_key() {
- MutexLocker m(mutex_);
- return private_key_;
- }
- bool set_private_key(SecKeyRef private_key) {
- MutexLocker m(mutex_);
- if (private_key_ != NULL) {
- return false;
- }
- private_key_ = private_key;
- return true;
- }
-
- SecKeychainRef keychain() {
- MutexLocker m(mutex_);
- return keychain_;
- }
- bool set_keychain(SecKeychainRef keychain) {
- MutexLocker m(mutex_);
- if (keychain_ != NULL) {
- return false;
- }
- keychain_ = keychain;
- return true;
- }
-
- CFArrayRef cert_chain() {
- MutexLocker m(mutex_);
- return cert_chain_;
- }
- bool set_cert_chain(CFArrayRef cert_chain) {
- MutexLocker m(mutex_);
- if (cert_chain_ != NULL) {
- return false;
- }
- cert_chain_ = cert_chain;
- return true;
- }
-
- CFArrayRef trusted_certs() {
- MutexLocker m(mutex_);
- return trusted_certs_;
- }
- bool set_trusted_certs(CFArrayRef trusted_certs) {
- MutexLocker m(mutex_);
- if (trusted_certs_ != NULL) {
- return false;
- }
- trusted_certs_ = trusted_certs;
- return true;
- }
-
- CFArrayRef cert_authorities() {
- MutexLocker m(mutex_);
- return cert_authorities_;
- }
- bool set_cert_authorities(CFArrayRef cert_authorities) {
- MutexLocker m(mutex_);
- if (cert_authorities_ != NULL) {
- return false;
- }
- cert_authorities_ = cert_authorities;
- return true;
- }
-
- bool trust_builtin() {
- MutexLocker m(mutex_);
- return trust_builtin_;
- }
- void set_trust_builtin(bool trust_builtin) {
- MutexLocker m(mutex_);
- trust_builtin_ = trust_builtin;
- }
-
- private:
- // The context is accessed both by Dart code and the IOService. This mutex
- // protects all fields.
- Mutex* mutex_;
-
- SecKeyRef private_key_;
- SecKeychainRef keychain_;
-
- // CFArrays of SecCertificateRef.
- CFArrayRef cert_chain_;
- CFArrayRef trusted_certs_;
- CFArrayRef cert_authorities_;
-
- bool trust_builtin_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
-};
-
-
static char* CFStringRefToCString(CFStringRef cfstring) {
CFIndex len = CFStringGetLength(cfstring);
CFIndex max_len =
@@ -257,7 +129,7 @@
Dart_WeakPersistentHandle handle,
void* context_pointer) {
SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
- delete filter;
+ filter->Release();
}
@@ -296,7 +168,7 @@
Dart_WeakPersistentHandle handle,
void* context_pointer) {
SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
- delete context;
+ context->Release();
}
@@ -679,7 +551,7 @@
SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
Dart_Handle err = SetFilter(args, filter);
if (Dart_IsError(err)) {
- delete filter;
+ filter->Release();
Dart_PropagateError(err);
}
err = filter->Init(dart_this);
@@ -791,7 +663,11 @@
void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
- intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
+ SSLFilter* filter = GetFilter(args);
+ // This filter pointer is passed to the IO Service thread. The IO Service
+ // thread must Release() the pointer when it is done with it.
+ filter->Retain();
+ intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
}
@@ -801,7 +677,7 @@
// cert_context deleted in DeleteCertContext finalizer.
Dart_Handle err = SetSecurityContext(args, cert_context);
if (Dart_IsError(err)) {
- delete cert_context;
+ cert_context->Release();
Dart_PropagateError(err);
}
}
@@ -995,7 +871,7 @@
reinterpret_cast<CFStringRef>(kSecOIDCommonName));
if (subject_name == NULL) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
- "X509.subject failed to find issuer's common name."));
+ "X509.subject failed to find subject's common name."));
} else {
Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_name));
}
@@ -1086,6 +962,8 @@
CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
CObjectIntptr filter_object(request[0]);
SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
+ RefCntReleaseScope<SSLFilter> rs(filter);
+
bool in_handshake = CObjectBool(request[1]).Value();
intptr_t starts[SSLFilter::kNumBuffers];
intptr_t ends[SSLFilter::kNumBuffers];
@@ -1514,7 +1392,7 @@
}
// Add the contexts to our wrapper.
- cert_context_ = context;
+ cert_context_.set(context);
ssl_context_ = ssl_context;
is_server_ = is_server;
@@ -1553,8 +1431,9 @@
}
CFArrayRef trusted_certs = NULL;
- if (cert_context_->trusted_certs() != NULL) {
- trusted_certs = CFArrayCreateCopy(NULL, cert_context_->trusted_certs());
+ if (cert_context_.get()->trusted_certs() != NULL) {
+ trusted_certs =
+ CFArrayCreateCopy(NULL, cert_context_.get()->trusted_certs());
} else {
trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
}
@@ -1572,11 +1451,11 @@
if (SSL_LOG_STATUS) {
Log::Print("Handshake %s built in root certs\n",
- cert_context_->trust_builtin() ? "trusting" : "not trusting");
+ cert_context_.get()->trust_builtin() ? "trusting" : "not trusting");
}
status = SecTrustSetAnchorCertificatesOnly(
- peer_trust, !cert_context_->trust_builtin());
+ peer_trust, !cert_context_.get()->trust_builtin());
if (status != noErr) {
CFRelease(trusted_certs);
CFRelease(peer_trust);
@@ -1619,7 +1498,7 @@
OSStatus SSLFilter::Handshake() {
- ASSERT(cert_context_ != NULL);
+ ASSERT(cert_context_.get() != NULL);
ASSERT(ssl_context_ != NULL);
// Try and push handshake along.
if (SSL_LOG_STATUS) {
@@ -1732,8 +1611,6 @@
SSLFilter::~SSLFilter() {
- // cert_context_ deleted by finalizer. Don't delete here.
- cert_context_ = NULL;
if (ssl_context_ != NULL) {
CFRelease(ssl_context_);
ssl_context_ = NULL;
diff --git a/runtime/bin/secure_socket_macos.h b/runtime/bin/secure_socket_macos.h
index c088d8c..b4fe635 100644
--- a/runtime/bin/secure_socket_macos.h
+++ b/runtime/bin/secure_socket_macos.h
@@ -20,6 +20,8 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/lockers.h"
+#include "bin/reference_counting.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
@@ -27,15 +29,144 @@
namespace dart {
namespace bin {
-// Forward declaration of SSLContext.
-class SSLCertContext;
+// SSLCertContext wraps the certificates needed for a SecureTransport
+// connection. Fields are protected by the mutex_ field, and may only be set
+// once. This is to allow access by both the Dart thread and the IOService
+// thread. Setters return false if the field was already set.
+class SSLCertContext : public ReferenceCounted<SSLCertContext> {
+ public:
+ SSLCertContext() :
+ ReferenceCounted(),
+ mutex_(new Mutex()),
+ private_key_(NULL),
+ keychain_(NULL),
+ cert_chain_(NULL),
+ trusted_certs_(NULL),
+ cert_authorities_(NULL),
+ trust_builtin_(false) {
+ }
+
+ ~SSLCertContext() {
+ {
+ MutexLocker m(mutex_);
+ if (private_key_ != NULL) {
+ CFRelease(private_key_);
+ }
+ if (keychain_ != NULL) {
+ SecKeychainDelete(keychain_);
+ CFRelease(keychain_);
+ }
+ if (cert_chain_ != NULL) {
+ CFRelease(cert_chain_);
+ }
+ if (trusted_certs_ != NULL) {
+ CFRelease(trusted_certs_);
+ }
+ if (cert_authorities_ != NULL) {
+ CFRelease(cert_authorities_);
+ }
+ }
+ delete mutex_;
+ }
+
+ SecKeyRef private_key() {
+ MutexLocker m(mutex_);
+ return private_key_;
+ }
+ bool set_private_key(SecKeyRef private_key) {
+ MutexLocker m(mutex_);
+ if (private_key_ != NULL) {
+ return false;
+ }
+ private_key_ = private_key;
+ return true;
+ }
+
+ SecKeychainRef keychain() {
+ MutexLocker m(mutex_);
+ return keychain_;
+ }
+ bool set_keychain(SecKeychainRef keychain) {
+ MutexLocker m(mutex_);
+ if (keychain_ != NULL) {
+ return false;
+ }
+ keychain_ = keychain;
+ return true;
+ }
+
+ CFArrayRef cert_chain() {
+ MutexLocker m(mutex_);
+ return cert_chain_;
+ }
+ bool set_cert_chain(CFArrayRef cert_chain) {
+ MutexLocker m(mutex_);
+ if (cert_chain_ != NULL) {
+ return false;
+ }
+ cert_chain_ = cert_chain;
+ return true;
+ }
+
+ CFArrayRef trusted_certs() {
+ MutexLocker m(mutex_);
+ return trusted_certs_;
+ }
+ bool set_trusted_certs(CFArrayRef trusted_certs) {
+ MutexLocker m(mutex_);
+ if (trusted_certs_ != NULL) {
+ return false;
+ }
+ trusted_certs_ = trusted_certs;
+ return true;
+ }
+
+ CFArrayRef cert_authorities() {
+ MutexLocker m(mutex_);
+ return cert_authorities_;
+ }
+ bool set_cert_authorities(CFArrayRef cert_authorities) {
+ MutexLocker m(mutex_);
+ if (cert_authorities_ != NULL) {
+ return false;
+ }
+ cert_authorities_ = cert_authorities;
+ return true;
+ }
+
+ bool trust_builtin() {
+ MutexLocker m(mutex_);
+ return trust_builtin_;
+ }
+ void set_trust_builtin(bool trust_builtin) {
+ MutexLocker m(mutex_);
+ trust_builtin_ = trust_builtin;
+ }
+
+ private:
+ // The context is accessed both by Dart code and the IOService. This mutex
+ // protects all fields.
+ Mutex* mutex_;
+
+ SecKeyRef private_key_;
+ SecKeychainRef keychain_;
+
+ // CFArrays of SecCertificateRef.
+ CFArrayRef cert_chain_;
+ CFArrayRef trusted_certs_;
+ CFArrayRef cert_authorities_;
+
+ bool trust_builtin_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
+};
// SSLFilter encapsulates the SecureTransport code in a filter that communicates
// with the containing _SecureFilterImpl Dart object through four shared
// ExternalByteArray buffers, for reading and writing plaintext, and
// reading and writing encrypted text. The filter handles handshaking
// and certificate verification.
-class SSLFilter {
+class SSLFilter : public ReferenceCounted<SSLFilter> {
public:
// These enums must agree with those in sdk/lib/io/secure_socket.dart.
enum BufferIndex {
@@ -48,7 +179,8 @@
};
SSLFilter()
- : cert_context_(NULL),
+ : ReferenceCounted(),
+ cert_context_(NULL),
ssl_context_(NULL),
peer_certs_(NULL),
string_start_(NULL),
@@ -117,7 +249,7 @@
OSStatus Handshake();
Dart_Handle InvokeBadCertCallback(SecCertificateRef peer_cert);
- SSLCertContext* cert_context_;
+ RetainedPointer<SSLCertContext> cert_context_;
SSLContextRef ssl_context_;
CFArrayRef peer_certs_;
@@ -143,64 +275,6 @@
DISALLOW_COPY_AND_ASSIGN(SSLFilter);
};
-// Where the argument to the constructor is the handle for an object
-// implementing List<int>, this class creates a scope in which the memory
-// backing the list can be accessed.
-//
-// Do not make Dart_ API calls while in a ScopedMemBuffer.
-// Do not call Dart_PropagateError while in a ScopedMemBuffer.
-class ScopedMemBuffer {
- public:
- explicit ScopedMemBuffer(Dart_Handle object) {
- if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Argument is not a List<int>"));
- }
-
- uint8_t* bytes = NULL;
- intptr_t bytes_len = 0;
- bool is_typed_data = false;
- if (Dart_IsTypedData(object)) {
- is_typed_data = true;
- Dart_TypedData_Type typ;
- ThrowIfError(Dart_TypedDataAcquireData(
- object,
- &typ,
- reinterpret_cast<void**>(&bytes),
- &bytes_len));
- } else {
- ASSERT(Dart_IsList(object));
- ThrowIfError(Dart_ListLength(object, &bytes_len));
- bytes = Dart_ScopeAllocate(bytes_len);
- ASSERT(bytes != NULL);
- ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len));
- }
-
- object_ = object;
- bytes_ = bytes;
- bytes_len_ = bytes_len;
- is_typed_data_ = is_typed_data;
- }
-
- ~ScopedMemBuffer() {
- if (is_typed_data_) {
- ThrowIfError(Dart_TypedDataReleaseData(object_));
- }
- }
-
- uint8_t* get() const { return bytes_; }
- intptr_t length() const { return bytes_len_; }
-
- private:
- Dart_Handle object_;
- uint8_t* bytes_;
- intptr_t bytes_len_;
- bool is_typed_data_;
-
- DISALLOW_ALLOCATION();
- DISALLOW_COPY_AND_ASSIGN(ScopedMemBuffer);
-};
-
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index fb9704b..7b6f95a 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -194,6 +194,11 @@
}
+void FUNCTION_NAME(NetworkInterface_ListSupported)(Dart_NativeArguments args) {
+ Dart_SetReturnValue(args, Dart_NewBoolean(Socket::ListInterfacesSupported()));
+}
+
+
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
RawAddr addr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 2cf940c..bd8ed4b 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -315,6 +315,9 @@
static bool ParseAddress(int type, const char* address, RawAddr* addr);
static bool FormatNumericAddress(const RawAddr& addr, char* address, int len);
+ // Whether ListInterfaces is supported.
+ static bool ListInterfacesSupported();
+
// List interfaces. Returns a AddressList of InterfaceSocketAddress's.
static AddressList<InterfaceSocketAddress>* ListInterfaces(
int type,
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index fd96a9a..b3e3fc4 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -331,11 +331,21 @@
}
+bool Socket::ListInterfacesSupported() {
+ return false;
+}
+
+
AddressList<InterfaceSocketAddress>* Socket::ListInterfaces(
int type,
OSError** os_error) {
// The ifaddrs.h header is not provided on Android. An Android
// implementation would have to use IOCTL or netlink.
+ ASSERT(*os_error == NULL);
+ *os_error = new OSError(-1,
+ "Listing interfaces is not supported "
+ "on this platform",
+ OSError::kSystem);
return NULL;
}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 1befb69..6393567 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -338,6 +338,11 @@
}
+bool Socket::ListInterfacesSupported() {
+ return true;
+}
+
+
AddressList<InterfaceSocketAddress>* Socket::ListInterfaces(
int type,
OSError** os_error) {
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 624da8e..708cd3c 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -336,6 +336,11 @@
}
+bool Socket::ListInterfacesSupported() {
+ return true;
+}
+
+
AddressList<InterfaceSocketAddress>* Socket::ListInterfaces(
int type,
OSError** os_error) {
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 1ec51b7..8025ab4 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -49,6 +49,10 @@
}
patch class NetworkInterface {
+ /* patch */ static bool get listSupported {
+ return _listSupported();
+ }
+
/* patch */ static Future<List<NetworkInterface>> list({
bool includeLoopback: false,
bool includeLinkLocal: false,
@@ -57,6 +61,8 @@
includeLinkLocal: includeLinkLocal,
type: type);
}
+
+ static bool _listSupported() native "NetworkInterface_ListSupported";
}
class _InternetAddress implements InternetAddress {
diff --git a/runtime/bin/socket_unsupported.cc b/runtime/bin/socket_unsupported.cc
index 933df53..0ea27f1 100644
--- a/runtime/bin/socket_unsupported.cc
+++ b/runtime/bin/socket_unsupported.cc
@@ -17,6 +17,12 @@
}
+void FUNCTION_NAME(NetworkInterface_ListSupported)(Dart_NativeArguments args) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Sockets unsupported on this platform"));
+}
+
+
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"Sockets unsupported on this platform"));
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index 4534c8c..e3d366d 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -411,6 +411,11 @@
}
+bool Socket::ListInterfacesSupported() {
+ return true;
+}
+
+
AddressList<InterfaceSocketAddress>* Socket::ListInterfaces(
int type,
OSError** os_error) {
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index f976190..dfe7307 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -17,8 +17,6 @@
'libdart_deps': ['libdart_lib_nosnapshot', 'libdart_lib',
'libdart_vm_nosnapshot', 'libdart_vm',
- 'libdart_vm_noopt',
- 'libdart_vm_precompiled_runtime',
'libdouble_conversion',],
},
'targets': [
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index a67f9e1..5835660 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2957,13 +2957,24 @@
bool reset_fields);
-DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshotAssembly(
uint8_t** vm_isolate_snapshot_buffer,
intptr_t* vm_isolate_snapshot_size,
uint8_t** isolate_snapshot_buffer,
intptr_t* isolate_snapshot_size,
- uint8_t** instructions_snapshot_buffer,
- intptr_t* instructions_snapshot_size);
+ uint8_t** instructions_assembly_buffer,
+ intptr_t* instructions_assembly_size);
+
+
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshotBlob(
+ uint8_t** vm_isolate_snapshot_buffer,
+ intptr_t* vm_isolate_snapshot_size,
+ uint8_t** isolate_snapshot_buffer,
+ intptr_t* isolate_snapshot_size,
+ uint8_t** instructions_blob_buffer,
+ intptr_t* instructions_blob_size,
+ uint8_t** rodata_blob_buffer,
+ intptr_t* rodata_blob_size);
DART_EXPORT bool Dart_IsRunningPrecompiledCode();
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart
index ae941b7..bc9b8f4 100644
--- a/runtime/lib/bigint.dart
+++ b/runtime/lib/bigint.dart
@@ -1336,16 +1336,6 @@
return str;
}
- _leftShiftWithMask32(int count, int mask) {
- if (_used == 0) return 0;
- if (count is! _Smi) {
- _shlFromInt(count); // Throws out of memory exception.
- }
- assert(_DIGIT_BITS == 32); // Otherwise this code needs to be revised.
- if (count > 31) return 0;
- return (_digits[0] << count) & mask;
- }
-
int _bitAndFromInteger(int other) {
return other._toBigint()._and(this)._toValidInt();
}
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index e75ecab..a1aa3bd 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -244,7 +244,7 @@
if (result.IsSmi()) {
return result.raw();
}
- return result.CheckAndCanonicalize(NULL);
+ return result.CheckAndCanonicalize(thread, NULL);
}
}
return default_value.raw();
@@ -290,28 +290,6 @@
}
-DEFINE_NATIVE_ENTRY(Integer_leftShiftWithMask32, 3) {
- const Integer& value = Integer::CheckedHandle(arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, shift_count, arguments->NativeArgAt(1));
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(2));
- ASSERT(CheckInteger(value));
- ASSERT(CheckInteger(shift_count));
- ASSERT(CheckInteger(mask));
- if (!shift_count.IsSmi()) {
- // Shift count is too large..
- const Instance& exception =
- Instance::Handle(isolate->object_store()->out_of_memory());
- Exceptions::Throw(thread, exception);
- }
- const Smi& smi_shift_count = Smi::Cast(shift_count);
- const Integer& shift_result = Integer::Handle(
- ShiftOperationHelper(Token::kSHL, value, smi_shift_count));
- const Integer& result =
- Integer::Handle(shift_result.BitOp(Token::kBIT_AND, mask));
- return result.AsValidInteger();
-}
-
-
DEFINE_NATIVE_ENTRY(Smi_shrFromInt, 2) {
const Smi& amount = Smi::CheckedHandle(arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index a28491c..a103f23 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -263,8 +263,6 @@
return string;
}
- _leftShiftWithMask32(count, mask) native "Integer_leftShiftWithMask32";
-
// Returns pow(this, e) % m.
int modPow(int e, int m) {
if (e is! int) {
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 40efc28..d10e066 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -2068,18 +2068,7 @@
ASSERT(cls.IsTypedefClass());
const Function& sig_func = Function::Handle(cls.signature_function());
Type& referent_type = Type::Handle(sig_func.SignatureType());
- // If the scope class of the function type is not generic, replace it with
- // Closure class (Function::SignatureType() keeps it).
ASSERT(cls.raw() == referent_type.type_class());
- if (!cls.IsGeneric()) {
- referent_type = Type::New(
- Class::Handle(Isolate::Current()->object_store()->closure_class()),
- TypeArguments::Handle(referent_type.arguments()),
- referent_type.token_pos());
- referent_type.set_signature(sig_func);
- referent_type ^= ClassFinalizer::FinalizeType(
- cls, referent_type, ClassFinalizer::kCanonicalize);
- }
referent_type ^= InstantiateType(referent_type, type);
return CreateFunctionTypeMirror(referent_type);
}
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index b61b6a6..7c4f5f5 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -73,8 +73,4 @@
});
return result;
}
-
- _leftShiftWithMask32(count, mask) {
- return (this << count) & mask;
- }
}
diff --git a/runtime/lib/string_buffer_patch.dart b/runtime/lib/string_buffer_patch.dart
index d087550..401d258 100644
--- a/runtime/lib/string_buffer_patch.dart
+++ b/runtime/lib/string_buffer_patch.dart
@@ -148,7 +148,8 @@
_partsCodeUnitsSinceCompaction += length;
if (_parts == null) {
- _parts = [ str ];
+ // Empirically this is a good capacity to minimize total bytes allocated.
+ _parts = new _GrowableList.withCapacity(10)..add(str);
} else {
_parts.add(str);
int partsSinceCompaction = _parts.length - _partsCompactionIndex;
diff --git a/runtime/observatory/lib/src/elements/code_view.dart b/runtime/observatory/lib/src/elements/code_view.dart
index d8fa1c7..037a9aa 100644
--- a/runtime/observatory/lib/src/elements/code_view.dart
+++ b/runtime/observatory/lib/src/elements/code_view.dart
@@ -28,6 +28,8 @@
DisassemblyTable disassemblyTable;
InlineTable inlineTable;
+ static const kDisassemblyColumnIndex = 3;
+
CodeViewElement.created() : super.created() {
// Create table models.
var columns = [
@@ -212,7 +214,20 @@
element.ref = content;
cell.children = [element];
} else if (content != null) {
- cell.text = content.toString();
+ String text = '$content';
+ if (i == kDisassemblyColumnIndex) {
+ // Disassembly might be a comment. Reduce indentation, change styling,
+ // widen to span next column (which should be empty).
+ if (text.startsWith(' ;;')) {
+ cell.attributes['colspan'] = '2';
+ cell.classes.add('code-comment');
+ text = text.substring(6);
+ } else {
+ cell.attributes['colspan'] = '1';
+ cell.classes.remove('code-comment');
+ }
+ }
+ cell.text = text;
}
}
}
diff --git a/runtime/observatory/lib/src/elements/code_view.html b/runtime/observatory/lib/src/elements/code_view.html
index ba4cac0..95f71e2 100644
--- a/runtime/observatory/lib/src/elements/code_view.html
+++ b/runtime/observatory/lib/src/elements/code_view.html
@@ -34,6 +34,7 @@
overflow: visible;
white-space: pre;
padding-right: 1em;
+ width: 1px;
}
th:nth-of-type(5), td:nth-of-type(5) {
@@ -45,6 +46,11 @@
background-color: #F4C7C3;
}
+ .code-comment {
+ color: grey;
+ font-style: italic;
+ }
+
</style>
<nav-bar>
<top-nav-menu></top-nav-menu>
diff --git a/runtime/observatory/tests/service/get_isolate_after_async_error_test.dart b/runtime/observatory/tests/service/get_isolate_after_async_error_test.dart
new file mode 100644
index 0000000..a0c531d
--- /dev/null
+++ b/runtime/observatory/tests/service/get_isolate_after_async_error_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2016, 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=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+
+doThrow() async {
+ throw "oh no"; // Line 13.
+}
+
+var tests = [
+ hasStoppedAtExit,
+
+ (Isolate isolate) async {
+ await isolate.reload();
+ expect(isolate.error, isNotNull);
+ expect(isolate.error.message.contains('oh no'), isTrue);
+ }
+];
+
+main(args) async => runIsolateTests(args,
+ tests,
+ pause_on_exit: true,
+ testeeConcurrent: doThrow);
\ No newline at end of file
diff --git a/runtime/observatory/tests/service/get_isolate_after_language_error_test.dart b/runtime/observatory/tests/service/get_isolate_after_language_error_test.dart
new file mode 100644
index 0000000..dc763a0
--- /dev/null
+++ b/runtime/observatory/tests/service/get_isolate_after_language_error_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, 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=--error_on_bad_type --error_on_bad_override
+
+import 'dart:async';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+
+var x;
+
+doThrow() {
+ if (x) while {
+ };
+}
+
+var tests = [
+ hasStoppedAtExit,
+
+ (Isolate isolate) async {
+ await isolate.reload();
+ expect(isolate.error, isNotNull);
+ expect(isolate.error.message.contains("'(' expected"), isTrue);
+ }
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+ tests,
+ pause_on_exit: true,
+ testeeConcurrent: doThrow);
\ No newline at end of file
diff --git a/runtime/observatory/tests/service/get_isolate_after_sync_error_test.dart b/runtime/observatory/tests/service/get_isolate_after_sync_error_test.dart
new file mode 100644
index 0000000..bf2684a
--- /dev/null
+++ b/runtime/observatory/tests/service/get_isolate_after_sync_error_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2016, 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=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+
+doThrow() {
+ throw "oh no"; // Line 13.
+}
+
+var tests = [
+ hasStoppedAtExit,
+
+ (Isolate isolate) async {
+ await isolate.reload();
+ expect(isolate.error, isNotNull);
+ expect(isolate.error.message.contains('oh no'), isTrue);
+ }
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+ tests,
+ pause_on_exit: true,
+ testeeConcurrent: doThrow);
\ No newline at end of file
diff --git a/runtime/observatory/tests/service/instance_field_order_rpc_test.dart b/runtime/observatory/tests/service/instance_field_order_rpc_test.dart
new file mode 100644
index 0000000..0323f8c
--- /dev/null
+++ b/runtime/observatory/tests/service/instance_field_order_rpc_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2016, 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=--error_on_bad_type --error_on_bad_override
+
+library get_object_rpc_test;
+
+import 'dart:typed_data';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+class Super {
+ var z = 1;
+ var y = 2;
+}
+class Sub extends Super {
+ var y = 3;
+ var x = 4;
+}
+
+eval(Isolate isolate, String expression) async {
+ Map params = {
+ 'targetId': isolate.rootLibrary.id,
+ 'expression': expression,
+ };
+ return await isolate.invokeRpcNoUpgrade('evaluate', params);
+}
+
+var tests = [
+ (Isolate isolate) async {
+ // Call eval to get a Dart list.
+ var evalResult = await eval(isolate, 'new Sub()');
+ var params = {
+ 'objectId': evalResult['id'],
+ };
+ var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+ print(result);
+ expect(result['type'], equals('Instance'));
+ expect(result['kind'], equals('PlainInstance'));
+ expect(result['class']['name'], equals('Sub'));
+ expect(result['size'], isPositive);
+ expect(result['fields'][0]['decl']['name'], 'z');
+ expect(result['fields'][0]['value']['valueAsString'], '1');
+ expect(result['fields'][1]['decl']['name'], 'y');
+ expect(result['fields'][1]['value']['valueAsString'], '2');
+ expect(result['fields'][2]['decl']['name'], 'y');
+ expect(result['fields'][2]['value']['valueAsString'], '3');
+ expect(result['fields'][3]['decl']['name'], 'x');
+ expect(result['fields'][3]['value']['valueAsString'], '4');
+ },
+];
+
+main(args) async => runIsolateTests(args, tests);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 8003189..bb742ac 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -5,6 +5,7 @@
[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) ]
evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
+isolate_lifecycle_test: Pass, RuntimeError # Issue 24174
# Disable on simulators.
[ $arch == simarm || $arch == simmips || $arch == simarm64]
@@ -21,6 +22,7 @@
address_mapper_test: Pass # https://github.com/dart-lang/observe/issues/85
command_test: Pass # https://github.com/dart-lang/observe/issues/85
read_stream_test: Pass # https://github.com/dart-lang/observe/issues/85
+get_isolate_after_language_error_test: SkipByDesign
[ $arch == arm ]
process_service_test: Pass, Fail # Issue 24344
@@ -36,8 +38,13 @@
*: SkipByDesign
# Service protocol is not supported when running a full application snapshot.
-[ ($runtime == dart_product) ]
+[ $runtime == dart_product ]
*: SkipByDesign
[ $compiler == dart2analyzer ]
evaluate_activation_in_method_class_test: CompileTimeError # Issue 24478
+
+[ $arch == simdbc || $arch == simdbc64 ]
+# TODO(vegorov) re-enable when debugger, coverage and profiling is completely
+# fixed for SIMDBC.
+*: Skip
diff --git a/runtime/observatory/tests/service/service_test_common.dart b/runtime/observatory/tests/service/service_test_common.dart
index 108316c..4a42290 100644
--- a/runtime/observatory/tests/service/service_test_common.dart
+++ b/runtime/observatory/tests/service/service_test_common.dart
@@ -140,6 +140,10 @@
return hasPausedFor(isolate, ServiceEvent.kPauseException);
}
+Future<Isolate> hasStoppedAtExit(Isolate isolate) {
+ return hasPausedFor(isolate, ServiceEvent.kPauseExit);
+}
+
Future<Isolate> hasPausedAtStart(Isolate isolate) {
return hasPausedFor(isolate, ServiceEvent.kPauseStart);
}
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 7e11bb3..a0dfdd0 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -2,8 +2,8 @@
// 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 PLATFORM_GLOBALS_H_
-#define PLATFORM_GLOBALS_H_
+#ifndef RUNTIME_PLATFORM_GLOBALS_H_
+#define RUNTIME_PLATFORM_GLOBALS_H_
// __STDC_FORMAT_MACROS has to be defined before including <inttypes.h> to
// enable platform independent printf format specifiers.
@@ -136,6 +136,10 @@
#endif // defined(PRODUCT)
+#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_PRECOMPILER)
+#error DART_PRECOMPILED_RUNTIME and DART_PRECOMPILER are mutually exclusive
+#endif // defined(DART_PRECOMPILED_RUNTIME) && defined(DART_PRECOMPILER)
+
namespace dart {
struct simd128_value_t {
@@ -257,6 +261,15 @@
#error Automatic compiler detection failed.
#endif
+// DART_NOINLINE tells compiler to never inline a particular function.
+#ifdef _MSC_VER
+#define DART_NOINLINE __declspec(noinline)
+#elif __GNUC__
+#define DART_NOINLINE __attribute__((noinline))
+#else
+#error Automatic compiler detection failed.
+#endif
+
// DART_UNUSED inidicates to the compiler that a variable/typedef is expected
// to be unused and disables the related warning.
#ifdef __GNUC__
@@ -282,6 +295,7 @@
#if !defined(TARGET_ARCH_X64)
#if !defined(TARGET_ARCH_IA32)
#if !defined(TARGET_ARCH_ARM64)
+#if !defined(TARGET_ARCH_DBC)
// No target architecture specified pick the one matching the host architecture.
#if defined(HOST_ARCH_MIPS)
#define TARGET_ARCH_MIPS 1
@@ -301,6 +315,7 @@
#endif
#endif
#endif
+#endif
// Verify that host and target architectures match, we cannot
// have a 64 bit Dart VM generating 32 bit code or vice-versa.
@@ -337,6 +352,9 @@
#define USING_SIMULATOR 1
#endif
+#elif defined(TARGET_ARCH_DBC)
+#define USING_SIMULATOR 1
+
#else
#error Unknown architecture.
#endif
@@ -660,4 +678,4 @@
} // namespace dart
-#endif // PLATFORM_GLOBALS_H_
+#endif // RUNTIME_PLATFORM_GLOBALS_H_
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 62cc6da..8de2b3b 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -33,7 +33,7 @@
cc/Dart2JSCompilerStats: Skip
cc/CorelibCompilerStats: Skip
-[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $arch == simmips ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $arch == simmips || $arch == simdbc || $arch == simdbc64 ]
cc/Service_Profile: Skip
[ $compiler == dart2js ]
@@ -97,3 +97,83 @@
cc/IsolateSetCheckedMode: Fail,OK # Expects exact type name.
cc/LibraryGetClassNames: Fail,OK # Expects exact type name.
cc/StackTraceFormat: Fail,OK # Expects exact type name.
+
+[ $arch == simdbc || $arch == simdbc64 ]
+# TODO(vegorov) Profiler is completely disabled in SIMDBC builds.
+cc/Profiler_AllocationSampleTest: Skip
+cc/Profiler_ArrayAllocation: Skip
+cc/Profiler_BasicSourcePosition: Skip
+cc/Profiler_BasicSourcePositionOptimized: Skip
+cc/Profiler_BinaryOperatorSourcePosition: Skip
+cc/Profiler_BinaryOperatorSourcePositionOptimized: Skip
+cc/Profiler_ChainedSamples: Skip
+cc/Profiler_ClosureAllocation: Skip
+cc/Profiler_CodeTicks: Skip
+cc/Profiler_ContextAllocation: Skip
+cc/Profiler_FunctionInline: Skip
+cc/Profiler_FunctionTicks: Skip
+cc/Profiler_InliningIntervalBoundry: Skip
+cc/Profiler_IntrinsicAllocation: Skip
+cc/Profiler_SampleBufferIterateTest: Skip
+cc/Profiler_SampleBufferWrapTest: Skip
+cc/Profiler_SourcePosition: Skip
+cc/Profiler_SourcePositionOptimized: Skip
+cc/Profiler_StringAllocation: Skip
+cc/Profiler_StringInterpolation: Skip
+cc/Profiler_ToggleRecordAllocation: Skip
+cc/Profiler_TrivialRecordAllocation: Skip
+cc/Profiler_TypedArrayAllocation: Skip
+cc/Profiler_GetSourceReport: Skip
+
+# TODO(vegorov) These tests are crashing because ICData objects can't be found
+cc/SourceReport_CallSites_PolymorphicCall: Skip
+cc/SourceReport_CallSites_SimpleCall: Skip
+cc/SourceReport_Coverage_AllFunctions: Skip
+cc/SourceReport_Coverage_ForceCompile: Skip
+cc/SourceReport_Coverage_NestedFunctions: Skip
+cc/SourceReport_Coverage_SimpleCall: Skip
+cc/SourceReport_MultipleReports: Skip
+cc/Coverage_Empty: Skip
+cc/Coverage_FilterFunction: Skip
+cc/Coverage_MainWithClass: Skip
+
+# TODO(vegorov) DisassembleToJSONStream requires
+# DecodeLoadObjectFromPoolOrThread which is unimplemented.
+cc/Service_Code: Skip
+cc/PrintJSON: Skip
+
+# TODO(vegorov) These tests don't seem to work if FLAG_interpret_irregexp
+# is switched on by default because they attempt to call regexp functions
+# directly instead of going through JSSyntaxRegExp_ExecuteMatch.
+cc/RegExp_ExternalOneByteString: Skip
+cc/RegExp_ExternalTwoByteString: Skip
+cc/RegExp_OneByteString: Skip
+cc/RegExp_TwoByteString: Skip
+
+# TODO(vegorov) Optimizing compiler is disabled for the SIMDBC
+cc/CompileFunctionOnHelperThread: Skip
+
+# TODO(vegorov) Field guards are disabled for SIMDBC
+cc/GuardFieldConstructor2Test: Skip
+cc/GuardFieldConstructorTest: Skip
+cc/GuardFieldFinalListTest: Skip
+cc/GuardFieldFinalVariableLengthListTest: Skip
+cc/GuardFieldSimpleTest: Skip
+
+# TODO(vegorov) Not all bytecodes have appropriate debug breaks.
+cc/Debug_BreakpointStubPatching: Skip
+cc/Debug_ExprClosureBreakpoint: Skip
+cc/Debug_StackTraceDump1: Skip
+cc/Debug_StepInto: Skip
+
+# TODO(vegorov) These parser tests rely on debugger.
+cc/Parser_AllocateVariables_CapturedVar: Skip
+cc/Parser_AllocateVariables_MiddleChain: Skip
+
+# This test is meaningless for DBC as allocation stubs are not used.
+cc/RegenerateAllocStubs: Skip
+
+# TODO(vegorov) Enable when DBC supports optimizing compiler.
+cc/Debug_InspectStack_Optimized: Skip
+cc/Debug_InspectStackWithClosure_Optimized: Skip
+
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index b19dfc8..b6e64db 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -18,7 +18,7 @@
static_library("libdart_platform") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config", "..:dart_product_config"]
public_configs = [":libdart_vm_config"]
platform_headers_gypi =
@@ -43,9 +43,10 @@
]
}
-
static_library("libdart_vm") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
public_configs = [":libdart_vm_config"]
vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
@@ -61,25 +62,29 @@
}
-static_library("libdart_vm_precompiled_runtime") {
- configs += ["..:dart_config_no_precompiler"]
- public_configs = [":libdart_vm_config"]
- defines = ["DART_PRECOMPILED_RUNTIME"]
- vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
- [rebase_path("vm_sources.gypi")],
- "scope",
- ["vm_sources.gypi"])
-
- set_sources_assignment_filter(["*_test.cc", "*_test.h"])
- sources = vm_sources_list.sources
- include_dirs = [
- "..",
- ]
-}
-
-
static_library("libdart_vm_nosnapshot") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
+ public_configs = [":libdart_vm_config"]
+ defines = [ "DART_NO_SNAPSHOT" ]
+ vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
+ [rebase_path("vm_sources.gypi")],
+ "scope",
+ ["vm_sources.gypi"])
+
+ set_sources_assignment_filter(["*_test.cc", "*_test.h"])
+ sources = vm_sources_list.sources
+ include_dirs = [
+ "..",
+ ]
+}
+
+
+static_library("libdart_vm_nosnapshot_with_precompiler") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiler_config"]
public_configs = [":libdart_vm_config"]
defines = [ "DART_NO_SNAPSHOT" ]
vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
@@ -185,24 +190,30 @@
}
static_library("libdart_lib_nosnapshot") {
- configs += ["..:dart_config"]
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
deps = libdeps
sources = libsources + ["bootstrap.cc"] + liboutputs
include_dirs = [
"..",
]
}
- static_library("libdart_lib") {
- configs += ["..:dart_config"]
- sources = libsources + [ "bootstrap_nocore.cc", ]
+ static_library("libdart_lib_nosnapshot_with_precompiler") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiler_config" ]
+ deps = libdeps
+ sources = libsources + [ "bootstrap.cc"] + liboutputs
include_dirs = [
"..",
]
}
- static_library("libdart_lib_precompiled_runtime") {
- configs += ["..:dart_config_no_precompiler"]
- defines = ["DART_PRECOMPILED_RUNTIME"]
- sources = libsources + [ "bootstrap_nocore.cc", ]
+ static_library("libdart_lib") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
+ sources = libsources + [ "bootstrap_nocore.cc"]
include_dirs = [
"..",
]
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 7d005b1..bc3bf8b 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -1904,71 +1904,6 @@
return TryInlineFloat64x2Method(call, recognized_kind);
}
- if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) {
- ASSERT(call->ArgumentCount() == 3);
- ASSERT(ic_data.NumArgsTested() == 2);
- Definition* value = call->ArgumentAt(0);
- Definition* count = call->ArgumentAt(1);
- Definition* int32_mask = call->ArgumentAt(2);
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
- if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
- return false;
- }
- // We cannot overflow. The input value must be a Smi
- AddCheckSmi(value, call->deopt_id(), call->env(), call);
- AddCheckSmi(count, call->deopt_id(), call->env(), call);
- ASSERT(int32_mask->IsConstant());
- const Integer& mask_literal = Integer::Cast(
- int32_mask->AsConstant()->value());
- const int64_t mask_value = mask_literal.AsInt64Value();
- ASSERT(mask_value >= 0);
- if (mask_value > Smi::kMaxValue) {
- // The result will not be Smi.
- return false;
- }
- BinarySmiOpInstr* left_shift =
- new(Z) BinarySmiOpInstr(Token::kSHL,
- new(Z) Value(value),
- new(Z) Value(count),
- call->deopt_id());
- left_shift->mark_truncating();
- if ((kBitsPerWord == 32) && (mask_value == 0xffffffffLL)) {
- // No BIT_AND operation needed.
- ReplaceCall(call, left_shift);
- } else {
- InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
- BinarySmiOpInstr* bit_and =
- new(Z) BinarySmiOpInstr(Token::kBIT_AND,
- new(Z) Value(left_shift),
- new(Z) Value(int32_mask),
- call->deopt_id());
- ReplaceCall(call, bit_and);
- }
- return true;
- }
-
- if (HasTwoMintOrSmi(ic_data) &&
- HasOnlyOneSmi(ICData::Handle(Z,
- ic_data.AsUnaryClassChecksForArgNr(1)))) {
- if (!FlowGraphCompiler::SupportsUnboxedMints() ||
- ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
- return false;
- }
- ShiftMintOpInstr* left_shift =
- new(Z) ShiftMintOpInstr(Token::kSHL,
- new(Z) Value(value),
- new(Z) Value(count),
- call->deopt_id());
- InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
- BinaryMintOpInstr* bit_and =
- new(Z) BinaryMintOpInstr(Token::kBIT_AND,
- new(Z) Value(left_shift),
- new(Z) Value(int32_mask),
- call->deopt_id());
- ReplaceCall(call, bit_and);
- return true;
- }
- }
return false;
}
diff --git a/runtime/vm/assembler.h b/runtime/vm/assembler.h
index 65820fe..ceaadaa 100644
--- a/runtime/vm/assembler.h
+++ b/runtime/vm/assembler.h
@@ -340,6 +340,8 @@
#include "vm/assembler_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/assembler_mips.h"
+#elif defined(TARGET_ARCH_DBC)
+#include "vm/assembler_dbc.h"
#else
#error Unknown architecture.
#endif
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 41ba7f5..db3314d 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1601,11 +1601,7 @@
: object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, pp, cond);
} else {
- ASSERT(FLAG_allow_absolute_addresses);
- ASSERT(object.IsOld());
- // Make sure that class CallPattern is able to decode this load immediate.
- const int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
- LoadImmediate(rd, object_raw, cond);
+ UNREACHABLE();
}
}
@@ -3408,38 +3404,23 @@
void Assembler::LoadAllocationStatsAddress(Register dest,
- intptr_t cid,
- bool inline_isolate) {
+ intptr_t cid) {
ASSERT(dest != kNoRegister);
ASSERT(dest != TMP);
ASSERT(cid > 0);
const intptr_t class_offset = ClassTable::ClassOffsetFor(cid);
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(dest, reinterpret_cast<uword>(*table_ptr) + class_offset);
- } else {
- LoadImmediate(dest, reinterpret_cast<uword>(table_ptr));
- ldr(dest, Address(dest, 0));
- AddImmediate(dest, class_offset);
- }
- } else {
- LoadIsolate(dest);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- ldr(dest, Address(dest, table_offset));
- AddImmediate(dest, class_offset);
- }
+ LoadIsolate(dest);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ ldr(dest, Address(dest, table_offset));
+ AddImmediate(dest, class_offset);
}
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace,
- bool inline_isolate) {
- LoadAllocationStatsAddress(temp_reg, cid, inline_isolate);
+ Label* trace) {
+ LoadAllocationStatsAddress(temp_reg, cid);
const uword state_offset = ClassHeapStats::state_offset();
ldr(temp_reg, Address(temp_reg, state_offset));
tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
@@ -3498,8 +3479,7 @@
// 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,
- /* inline_isolate = */ false);
+ MaybeTraceAllocation(cls.id(), temp_reg, failure);
Heap::Space space = Heap::SpaceForAllocation(cls.id());
ldr(temp_reg, Address(THR, Thread::heap_offset()));
ldr(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
@@ -3516,8 +3496,7 @@
// next object start and store the class in the class field of object.
str(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
- LoadAllocationStatsAddress(temp_reg, cls.id(),
- /* inline_isolate = */ false);
+ LoadAllocationStatsAddress(temp_reg, cls.id());
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
@@ -3547,7 +3526,7 @@
// 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, /* inline_isolate = */ false);
+ MaybeTraceAllocation(cid, temp1, failure);
Heap::Space space = Heap::SpaceForAllocation(cid);
ldr(temp1, Address(THR, Thread::heap_offset()));
// Potential new object start.
@@ -3562,7 +3541,7 @@
cmp(end_address, Operand(temp2));
b(failure, CS);
- LoadAllocationStatsAddress(temp2, cid, /* inline_isolate = */ false);
+ 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 a85dd43..66e7c13 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -976,8 +976,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,
- bool inline_isolate = true);
+ intptr_t cid);
void IncrementAllocationStats(Register stats_addr,
intptr_t cid,
Heap::Space space);
@@ -1004,8 +1003,7 @@
// which will allocate in the runtime where tracing occurs.
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace,
- bool inline_isolate = true);
+ 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.
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 28dc872..eeb831d 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -413,8 +413,7 @@
: object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(dst, offset);
} else {
- ASSERT(object.IsSmi() || object.InVMHeap());
- ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
+ ASSERT(object.IsSmi());
LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()));
}
}
@@ -452,7 +451,7 @@
LoadObject(TMP, object);
CompareRegisters(reg, TMP);
} else {
- ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
+ ASSERT(object.IsSmi());
CompareImmediate(reg, reinterpret_cast<int64_t>(object.raw()));
}
}
@@ -1264,30 +1263,15 @@
void Assembler::UpdateAllocationStats(intptr_t cid,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
intptr_t counter_offset =
ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(
- TMP2, reinterpret_cast<uword>(*table_ptr) + counter_offset);
- } else {
- LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr));
- ldr(TMP, Address(TMP2));
- AddImmediate(TMP2, TMP, counter_offset);
- }
- } else {
- LoadIsolate(TMP2);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- ldr(TMP, Address(TMP2, table_offset));
- AddImmediate(TMP2, TMP, counter_offset);
- }
+ LoadIsolate(TMP2);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ ldr(TMP, Address(TMP2, table_offset));
+ AddImmediate(TMP2, TMP, counter_offset);
ldr(TMP, Address(TMP2, 0));
AddImmediate(TMP, TMP, 1);
str(TMP, Address(TMP2, 0));
@@ -1296,8 +1280,7 @@
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
const uword class_offset = ClassTable::ClassOffsetFor(cid);
const uword count_field_offset = (space == Heap::kNew) ?
@@ -1306,24 +1289,11 @@
const uword size_field_offset = (space == Heap::kNew) ?
ClassHeapStats::allocated_size_since_gc_new_space_offset() :
ClassHeapStats::allocated_size_since_gc_old_space_offset();
- if (inline_isolate) {
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(TMP2,
- reinterpret_cast<uword>(*table_ptr) + class_offset);
- } else {
- LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr));
- ldr(TMP, Address(TMP2));
- AddImmediate(TMP2, TMP, class_offset);
- }
- } else {
- LoadIsolate(TMP2);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- ldr(TMP, Address(TMP2, table_offset));
- AddImmediate(TMP2, TMP, class_offset);
- }
+ LoadIsolate(TMP2);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ ldr(TMP, Address(TMP2, table_offset));
+ AddImmediate(TMP2, TMP, class_offset);
ldr(TMP, Address(TMP2, count_field_offset));
AddImmediate(TMP, TMP, 1);
str(TMP, Address(TMP2, count_field_offset));
@@ -1335,29 +1305,14 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace,
- bool inline_isolate) {
+ Label* trace) {
ASSERT(cid > 0);
intptr_t state_offset = ClassTable::StateOffsetFor(cid);
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(
- temp_reg, reinterpret_cast<uword>(*table_ptr) + state_offset);
- } else {
- LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr));
- ldr(temp_reg, Address(temp_reg, 0));
- AddImmediate(temp_reg, temp_reg, state_offset);
- }
- } else {
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- ldr(temp_reg, Address(temp_reg, table_offset));
- AddImmediate(temp_reg, temp_reg, state_offset);
- }
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ ldr(temp_reg, Address(temp_reg, table_offset));
+ AddImmediate(temp_reg, temp_reg, state_offset);
ldr(temp_reg, Address(temp_reg, 0));
tsti(temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
b(trace, NE);
@@ -1373,8 +1328,7 @@
// 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,
- /* inline_isolate = */ false);
+ MaybeTraceAllocation(cls.id(), temp_reg, failure);
const intptr_t instance_size = cls.instance_size();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
ldr(temp_reg, Address(THR, Thread::heap_offset()));
@@ -1395,7 +1349,7 @@
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(
instance_reg, instance_reg, -instance_size + kHeapObjectTag);
- UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
+ UpdateAllocationStats(cls.id(), space);
uword tags = 0;
tags = RawObject::SizeTag::update(instance_size, tags);
@@ -1420,7 +1374,7 @@
// 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, /* inline_isolate = */ false);
+ MaybeTraceAllocation(cid, temp1, failure);
Heap::Space space = Heap::SpaceForAllocation(cid);
ldr(temp1, Address(THR, Thread::heap_offset()));
// Potential new object start.
@@ -1440,8 +1394,7 @@
str(end_address, Address(temp1, Heap::TopOffset(space)));
add(instance, instance, Operand(kHeapObjectTag));
LoadImmediate(temp2, instance_size);
- UpdateAllocationStatsWithSize(cid, temp2, space,
- /* inline_isolate = */ false);
+ UpdateAllocationStatsWithSize(cid, temp2, space);
// Initialize the tags.
// instance: new object start as a tagged pointer.
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index ee8eb70..735e07e 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1378,20 +1378,17 @@
void LeaveStubFrame();
void UpdateAllocationStats(intptr_t cid,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ 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,
- Label* trace,
- bool inline_isolate = true);
+ 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.
diff --git a/runtime/vm/assembler_dbc.cc b/runtime/vm/assembler_dbc.cc
new file mode 100644
index 0000000..f35d1d5
--- /dev/null
+++ b/runtime/vm/assembler_dbc.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h" // NOLINT
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/assembler.h"
+#include "vm/cpu.h"
+#include "vm/longjump.h"
+#include "vm/runtime_entry.h"
+#include "vm/simulator.h"
+#include "vm/stack_frame.h"
+#include "vm/stub_code.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, check_code_pointer);
+DECLARE_FLAG(bool, inline_alloc);
+
+void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
+ const uword end = data + length;
+ while (data < end) {
+ *reinterpret_cast<int32_t*>(data) = Bytecode::kTrap;
+ data += sizeof(int32_t);
+ }
+}
+
+#define DEFINE_EMIT(Name, Signature, Fmt0, Fmt1, Fmt2) \
+ void Assembler::Name(PARAMS_##Signature) { \
+ Emit(Bytecode::FENCODE_##Signature( \
+ Bytecode::k##Name ENCODE_##Signature)); \
+ } \
+
+
+#define PARAMS_0
+#define PARAMS_A_D uintptr_t ra, uintptr_t rd
+#define PARAMS_D uintptr_t rd
+#define PARAMS_A_B_C uintptr_t ra, uintptr_t rb, uintptr_t rc
+#define PARAMS_A uintptr_t ra
+#define PARAMS_T intptr_t x
+#define PARAMS_A_X uintptr_t ra, intptr_t x
+#define PARAMS_X intptr_t x
+
+#define ENCODE_0
+#define ENCODE_A_D , ra, rd
+#define ENCODE_D , 0, rd
+#define ENCODE_A_B_C , ra, rb, rc
+#define ENCODE_A , ra, 0
+#define ENCODE_T , x
+#define ENCODE_A_X , ra, x
+#define ENCODE_X , 0, x
+
+#define FENCODE_0 Encode
+#define FENCODE_A_D Encode
+#define FENCODE_D Encode
+#define FENCODE_A_B_C Encode
+#define FENCODE_A Encode
+#define FENCODE_T EncodeSigned
+#define FENCODE_A_X EncodeSigned
+#define FENCODE_X EncodeSigned
+
+
+BYTECODES_LIST(DEFINE_EMIT)
+
+
+#undef DEFINE_EMIT
+
+
+void Assembler::Emit(int32_t value) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ buffer_.Emit<int32_t>(value);
+}
+
+
+const char* Assembler::RegisterName(Register reg) {
+ return Thread::Current()->zone()->PrintToString("R%d", reg);
+}
+
+
+static int32_t EncodeJump(int32_t relative_pc) {
+ return Bytecode::kJump | (relative_pc << 8);
+}
+
+
+static int32_t OffsetToPC(int32_t offset) {
+ return offset >> 2;
+}
+
+
+void Assembler::Jump(Label* label) {
+ if (label->IsBound()) {
+ Emit(EncodeJump(OffsetToPC(label->Position() - buffer_.Size())));
+ } else {
+ const intptr_t position = buffer_.Size();
+ Emit(label->position_);
+ label->LinkTo(position);
+ }
+}
+
+
+void Assembler::Bind(Label* label) {
+ ASSERT(!label->IsBound());
+ ASSERT(!label->IsBound());
+ intptr_t bound_pc = buffer_.Size();
+ while (label->IsLinked()) {
+ const int32_t position = label->Position();
+ const int32_t next_position = buffer_.Load<int32_t>(position);
+ buffer_.Store<int32_t>(position,
+ EncodeJump(OffsetToPC(bound_pc - position)));
+ label->position_ = next_position;
+ }
+ label->BindTo(bound_pc);
+}
+
+
+void Assembler::Stop(const char* message) {
+ // TODO(vegorov) support passing a message to the bytecode.
+ Emit(Bytecode::kTrap);
+}
+
+
+void Assembler::PushConstant(const Object& obj) {
+ PushConstant(AddConstant(obj));
+}
+
+
+void Assembler::LoadConstant(uintptr_t ra, const Object& obj) {
+ LoadConstant(ra, AddConstant(obj));
+}
+
+
+intptr_t Assembler::AddConstant(const Object& obj) {
+ return object_pool_wrapper().FindObject(
+ Object::ZoneHandle(obj.raw()));
+}
+
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/assembler_dbc.h b/runtime/vm/assembler_dbc.h
new file mode 100644
index 0000000..590dd5c
--- /dev/null
+++ b/runtime/vm/assembler_dbc.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2016, 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_ASSEMBLER_DBC_H_
+#define VM_ASSEMBLER_DBC_H_
+
+#ifndef VM_ASSEMBLER_H_
+#error Do not include assembler_dbc.h directly; use assembler.h instead.
+#endif
+
+#include "platform/assert.h"
+#include "platform/utils.h"
+#include "vm/constants_dbc.h"
+#include "vm/cpu.h"
+#include "vm/hash_map.h"
+#include "vm/object.h"
+#include "vm/simulator.h"
+
+namespace dart {
+
+
+// Dummy declaration to make things compile.
+class Address : public ValueObject {
+ private:
+ Address();
+};
+
+
+class Label : public ValueObject {
+ public:
+ Label() : position_(0) { }
+
+ ~Label() {
+ // Assert if label is being destroyed with unresolved branches pending.
+ ASSERT(!IsLinked());
+ }
+
+ // Returns the position for bound and linked labels. Cannot be used
+ // for unused labels.
+ intptr_t Position() const {
+ ASSERT(!IsUnused());
+ return IsBound() ? -position_ - kWordSize : position_ - kWordSize;
+ }
+
+ bool IsBound() const { return position_ < 0; }
+ bool IsUnused() const { return position_ == 0; }
+ bool IsLinked() const { return position_ > 0; }
+
+ private:
+ intptr_t position_;
+
+ void Reinitialize() {
+ position_ = 0;
+ }
+
+ void BindTo(intptr_t position) {
+ ASSERT(!IsBound());
+ position_ = -position - kWordSize;
+ ASSERT(IsBound());
+ }
+
+ void LinkTo(intptr_t position) {
+ ASSERT(!IsBound());
+ position_ = position + kWordSize;
+ ASSERT(IsLinked());
+ }
+
+ friend class Assembler;
+ DISALLOW_COPY_AND_ASSIGN(Label);
+};
+
+
+class Assembler : public ValueObject {
+ public:
+ explicit Assembler(bool use_far_branches = false)
+ : buffer_(),
+ comments_() {
+ }
+
+ ~Assembler() { }
+
+ void Bind(Label* label);
+ void Jump(Label* label);
+
+ // Misc. functionality
+ intptr_t CodeSize() const { return buffer_.Size(); }
+ intptr_t prologue_offset() const { return 0; }
+
+ // Count the fixups that produce a pointer offset, without processing
+ // the fixups.
+ intptr_t CountPointerOffsets() const { return 0; }
+
+ const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const {
+ ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code.
+ return buffer_.pointer_offsets();
+ }
+
+ ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; }
+
+ RawObjectPool* MakeObjectPool() {
+ return object_pool_wrapper_.MakeObjectPool();
+ }
+
+ void FinalizeInstructions(const MemoryRegion& region) {
+ buffer_.FinalizeInstructions(region);
+ }
+
+ // Debugging and bringup support.
+ void Stop(const char* message);
+ void Unimplemented(const char* message);
+ void Untested(const char* message);
+ void Unreachable(const char* message);
+
+ static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
+
+ void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+ static bool EmittingComments();
+
+ const Code::Comments& GetCodeComments() const;
+
+ static const char* RegisterName(Register reg);
+
+ static const char* FpuRegisterName(FpuRegister reg) {
+ return "?";
+ }
+
+ static uword GetBreakInstructionFiller() {
+ return Bytecode::kTrap;
+ }
+
+ static bool IsSafe(const Object& value) { return true; }
+ static bool IsSafeSmi(const Object& value) { return false; }
+
+ // Bytecodes.
+
+#define DECLARE_EMIT(Name, Signature, Fmt0, Fmt1, Fmt2) \
+ void Name(PARAMS_##Signature);
+
+#define PARAMS_0
+#define PARAMS_A_D uintptr_t ra, uintptr_t rd
+#define PARAMS_D uintptr_t rd
+#define PARAMS_A_B_C uintptr_t ra, uintptr_t rb, uintptr_t rc
+#define PARAMS_A uintptr_t ra
+#define PARAMS_X intptr_t x
+#define PARAMS_T intptr_t x
+#define PARAMS_A_X uintptr_t ra, intptr_t x
+
+
+ BYTECODES_LIST(DECLARE_EMIT)
+
+#undef PARAMS_0
+#undef PARAMS_A_D
+#undef PARAMS_D
+#undef PARAMS_A_B_C
+#undef PARAMS_A
+#undef PARAMS_X
+#undef PARAMS_T
+#undef PARAMS_A_X
+#undef DECLARE_EMIT
+
+ void Emit(int32_t value);
+
+ void PushConstant(const Object& obj);
+ void LoadConstant(uintptr_t ra, const Object& obj);
+
+ intptr_t AddConstant(const Object& obj);
+
+ private:
+ AssemblerBuffer buffer_; // Contains position independent code.
+ ObjectPoolWrapper object_pool_wrapper_;
+
+ class CodeComment : public ZoneAllocated {
+ public:
+ CodeComment(intptr_t pc_offset, const String& comment)
+ : pc_offset_(pc_offset), comment_(comment) { }
+
+ intptr_t pc_offset() const { return pc_offset_; }
+ const String& comment() const { return comment_; }
+
+ private:
+ intptr_t pc_offset_;
+ const String& comment_;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeComment);
+ };
+
+ GrowableArray<CodeComment*> comments_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(Assembler);
+};
+
+
+} // namespace dart
+
+#endif // VM_ASSEMBLER_DBC_H_
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index b9e80d0..e8851ac 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2704,32 +2704,16 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
Label* trace,
- bool near_jump,
- bool inline_isolate) {
+ bool near_jump) {
ASSERT(cid > 0);
Address state_address(kNoRegister, 0);
intptr_t state_offset = ClassTable::StateOffsetFor(cid);
- if (inline_isolate) {
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- state_address = Address::Absolute(
- reinterpret_cast<uword>(*table_ptr) + state_offset);
- } else {
- ASSERT(temp_reg != kNoRegister);
- // temp_reg gets address of class table pointer.
- movl(temp_reg,
- Address::Absolute(reinterpret_cast<uword>(table_ptr)));
- state_address = Address(temp_reg, state_offset);
- }
- } else {
- ASSERT(temp_reg != kNoRegister);
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- movl(temp_reg, Address(temp_reg, table_offset));
- state_address = Address(temp_reg, state_offset);
- }
+ ASSERT(temp_reg != kNoRegister);
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ movl(temp_reg, Address(temp_reg, table_offset));
+ state_address = Address(temp_reg, 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.
@@ -2739,71 +2723,40 @@
void Assembler::UpdateAllocationStats(intptr_t cid,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
intptr_t counter_offset =
ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
- if (inline_isolate) {
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- incl(Address::Absolute(
- reinterpret_cast<uword>(*table_ptr) + counter_offset));
- } else {
- ASSERT(temp_reg != kNoRegister);
- movl(temp_reg,
- Address::Absolute(reinterpret_cast<uword>(table_ptr)));
- incl(Address(temp_reg, counter_offset));
- }
- } else {
- ASSERT(temp_reg != kNoRegister);
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- movl(temp_reg, Address(temp_reg, table_offset));
- incl(Address(temp_reg, counter_offset));
- }
+ ASSERT(temp_reg != kNoRegister);
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ movl(temp_reg, Address(temp_reg, table_offset));
+ incl(Address(temp_reg, counter_offset));
}
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
ASSERT(cid < kNumPredefinedCids);
- UpdateAllocationStats(cid, temp_reg, space, inline_isolate);
+ UpdateAllocationStats(cid, temp_reg, space);
intptr_t size_offset = ClassTable::SizeOffsetFor(cid, space == Heap::kNew);
- if (inline_isolate) {
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- addl(Address::Absolute(
- reinterpret_cast<uword>(*table_ptr) + size_offset), size_reg);
- } else {
- addl(Address(temp_reg, size_offset), size_reg);
- }
+ addl(Address(temp_reg, size_offset), size_reg);
}
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
intptr_t size_in_bytes,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
ASSERT(cid < kNumPredefinedCids);
- UpdateAllocationStats(cid, temp_reg, space, inline_isolate);
+ UpdateAllocationStats(cid, temp_reg, space);
intptr_t size_offset = ClassTable::SizeOffsetFor(cid, space == Heap::kNew);
- if (inline_isolate) {
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- addl(Address::Absolute(reinterpret_cast<uword>(*table_ptr) + size_offset),
- Immediate(size_in_bytes));
- } else {
- addl(Address(temp_reg, size_offset), Immediate(size_in_bytes));
- }
+ addl(Address(temp_reg, size_offset), Immediate(size_in_bytes));
}
@@ -2818,8 +2771,7 @@
// 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,
- /* inline_isolate = */ false);
+ MaybeTraceAllocation(cls.id(), temp_reg, failure, near_jump);
const intptr_t instance_size = cls.instance_size();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
movl(temp_reg, Address(THR, Thread::heap_offset()));
@@ -2831,8 +2783,7 @@
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
movl(Address(temp_reg, Heap::TopOffset(space)), instance_reg);
- UpdateAllocationStats(cls.id(), temp_reg, space,
- /* inline_isolate = */ false);
+ UpdateAllocationStats(cls.id(), temp_reg, space);
ASSERT(instance_size >= kHeapObjectTag);
subl(instance_reg, Immediate(instance_size - kHeapObjectTag));
uword tags = 0;
@@ -2859,8 +2810,7 @@
// 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, temp_reg, failure, near_jump,
- /* inline_isolate = */ false);
+ MaybeTraceAllocation(cid, temp_reg, failure, near_jump);
Heap::Space space = Heap::SpaceForAllocation(cid);
movl(temp_reg, Address(THR, Thread::heap_offset()));
movl(instance, Address(temp_reg, Heap::TopOffset(space)));
@@ -2879,8 +2829,7 @@
// next object start and initialize the object.
movl(Address(temp_reg, Heap::TopOffset(space)), end_address);
addl(instance, Immediate(kHeapObjectTag));
- UpdateAllocationStatsWithSize(cid, instance_size, temp_reg, space,
- /* inline_isolate = */ false);
+ UpdateAllocationStatsWithSize(cid, instance_size, temp_reg, space);
// Initialize the tags.
uword tags = 0;
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 536a06e..5753792 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -892,24 +892,20 @@
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
Label* trace,
- bool near_jump,
- bool inline_isolate = true);
+ bool near_jump);
void UpdateAllocationStats(intptr_t cid,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
intptr_t instance_size,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 68794ed..c9c6549 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -588,14 +588,7 @@
: object_pool_wrapper_.FindObject(object));
LoadWordFromPoolOffset(rd, offset - kHeapObjectTag);
} else {
- ASSERT(FLAG_allow_absolute_addresses);
- ASSERT(object.IsOld());
- // Make sure that class CallPattern is able to decode this load immediate.
- int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
- const uint16_t object_low = Utils::Low16Bits(object_raw);
- const uint16_t object_high = Utils::High16Bits(object_raw);
- lui(rd, Immediate(object_high));
- ori(rd, rd, Immediate(object_low));
+ UNREACHABLE();
}
}
@@ -912,34 +905,18 @@
void Assembler::UpdateAllocationStats(intptr_t cid,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(!in_delay_slot_);
ASSERT(temp_reg != kNoRegister);
ASSERT(temp_reg != TMP);
ASSERT(cid > 0);
intptr_t counter_offset =
ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(
- temp_reg, reinterpret_cast<uword>(*table_ptr) + counter_offset);
- } else {
- ASSERT(temp_reg != kNoRegister);
- LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr));
- lw(temp_reg, Address(temp_reg, 0));
- AddImmediate(temp_reg, counter_offset);
- }
- } else {
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- lw(temp_reg, Address(temp_reg, table_offset));
- AddImmediate(temp_reg, counter_offset);
- }
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ lw(temp_reg, Address(temp_reg, table_offset));
+ AddImmediate(temp_reg, counter_offset);
lw(TMP, Address(temp_reg, 0));
AddImmediate(TMP, 1);
sw(TMP, Address(temp_reg, 0));
@@ -949,8 +926,7 @@
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(!in_delay_slot_);
ASSERT(temp_reg != kNoRegister);
ASSERT(cid > 0);
@@ -962,25 +938,11 @@
const uword size_field_offset = (space == Heap::kNew) ?
ClassHeapStats::allocated_size_since_gc_new_space_offset() :
ClassHeapStats::allocated_size_since_gc_old_space_offset();
- if (inline_isolate) {
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(temp_reg,
- reinterpret_cast<uword>(*table_ptr) + class_offset);
- } else {
- ASSERT(temp_reg != kNoRegister);
- LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr));
- lw(temp_reg, Address(temp_reg, 0));
- AddImmediate(temp_reg, class_offset);
- }
- } else {
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- lw(temp_reg, Address(temp_reg, table_offset));
- AddImmediate(temp_reg, class_offset);
- }
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ lw(temp_reg, Address(temp_reg, table_offset));
+ AddImmediate(temp_reg, class_offset);
lw(TMP, Address(temp_reg, count_field_offset));
AddImmediate(TMP, 1);
sw(TMP, Address(temp_reg, count_field_offset));
@@ -992,32 +954,17 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace,
- bool inline_isolate) {
+ Label* trace) {
ASSERT(cid > 0);
ASSERT(!in_delay_slot_);
ASSERT(temp_reg != kNoRegister);
ASSERT(temp_reg != TMP);
intptr_t state_offset = ClassTable::StateOffsetFor(cid);
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(temp_reg,
- reinterpret_cast<uword>(*table_ptr) + state_offset);
- } else {
- LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr));
- lw(temp_reg, Address(temp_reg, 0));
- AddImmediate(temp_reg, state_offset);
- }
- } else {
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- lw(temp_reg, Address(temp_reg, table_offset));
- AddImmediate(temp_reg, state_offset);
- }
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ lw(temp_reg, Address(temp_reg, table_offset));
+ AddImmediate(temp_reg, state_offset);
lw(temp_reg, Address(temp_reg, 0));
andi(CMPRES1, temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
bne(CMPRES1, ZR, trace);
@@ -1034,8 +981,7 @@
// 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,
- /* inline_isolate = */ false);
+ MaybeTraceAllocation(cls.id(), temp_reg, failure);
const intptr_t instance_size = cls.instance_size();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
lw(temp_reg, Address(THR, Thread::heap_offset()));
@@ -1054,8 +1000,7 @@
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
- UpdateAllocationStats(cls.id(), temp_reg, space,
- /* inline_isolate = */ false);
+ UpdateAllocationStats(cls.id(), temp_reg, space);
uword tags = 0;
tags = RawObject::SizeTag::update(instance_size, tags);
ASSERT(cls.id() != kIllegalCid);
@@ -1079,7 +1024,7 @@
// 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, /* inline_isolate = */ false);
+ MaybeTraceAllocation(cid, temp1, failure);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
@@ -1102,8 +1047,7 @@
sw(end_address, Address(temp1, Heap::TopOffset(space)));
addiu(instance, instance, Immediate(kHeapObjectTag));
LoadImmediate(temp1, instance_size);
- UpdateAllocationStatsWithSize(cid, temp1, temp2, space,
- /* inline_isolate = */ false);
+ UpdateAllocationStatsWithSize(cid, temp1, temp2, space);
// Initialize the tags.
// instance: new object start as a tagged pointer.
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 4e4f7f3..39b06a4 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -297,20 +297,17 @@
void UpdateAllocationStats(intptr_t cid,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
Register temp_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace,
- bool inline_isolate = true);
+ 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.
diff --git a/runtime/vm/assembler_test.cc b/runtime/vm/assembler_test.cc
index fbbd994..88ff667 100644
--- a/runtime/vm/assembler_test.cc
+++ b/runtime/vm/assembler_test.cc
@@ -11,6 +11,8 @@
namespace dart {
+// TODO(vegorov) assembler part of this test is not implemented.
+#if !defined(TARGET_ARCH_DBC)
ASSEMBLER_TEST_EXTERN(StoreIntoObject);
ASSEMBLER_TEST_RUN(StoreIntoObject, test) {
@@ -60,5 +62,6 @@
EXPECT(old_array.raw() == grow_new_array.data());
EXPECT(!thread->StoreBufferContains(grow_new_array.raw()));
}
+#endif
} // namespace dart
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 478c2ae..67bc237 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -2803,8 +2803,7 @@
const int32_t offset = ObjectPool::element_offset(idx);
LoadWordFromPoolOffset(dst, offset - kHeapObjectTag);
} else {
- ASSERT(object.IsSmi() || object.InVMHeap());
- ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
+ ASSERT(object.IsSmi());
LoadImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
@@ -2841,7 +2840,7 @@
LoadObject(TMP, object);
movq(dst, TMP);
} else {
- ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
+ ASSERT(object.IsSmi());
MoveImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
@@ -2856,7 +2855,7 @@
LoadObject(TMP, object);
pushq(TMP);
} else {
- ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
+ ASSERT(object.IsSmi());
PushImmediate(Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
@@ -2872,7 +2871,7 @@
const int32_t offset = ObjectPool::element_offset(idx);
cmpq(reg, Address(PP, offset-kHeapObjectTag));
} else {
- ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
+ ASSERT(object.IsSmi());
CompareImmediate(
reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
@@ -3458,27 +3457,14 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Label* trace,
- bool near_jump,
- bool inline_isolate) {
+ bool near_jump) {
ASSERT(cid > 0);
intptr_t state_offset = ClassTable::StateOffsetFor(cid);
Register temp_reg = TMP;
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- movq(temp_reg, Immediate(reinterpret_cast<uword>(*table_ptr)));
- } else {
- movq(temp_reg, Immediate(reinterpret_cast<uword>(table_ptr)));
- movq(temp_reg, Address(temp_reg, 0));
- }
- } else {
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- movq(temp_reg, Address(temp_reg, table_offset));
- }
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ movq(temp_reg, Address(temp_reg, table_offset));
testb(Address(temp_reg, state_offset),
Immediate(ClassHeapStats::TraceAllocationMask()));
// We are tracing for this class, jump to the trace label which will use
@@ -3488,39 +3474,25 @@
void Assembler::UpdateAllocationStats(intptr_t cid,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
intptr_t counter_offset =
ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
Register temp_reg = TMP;
- if (inline_isolate) {
- ASSERT(FLAG_allow_absolute_addresses);
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
- if (cid < kNumPredefinedCids) {
- movq(temp_reg, Immediate(reinterpret_cast<uword>(*table_ptr)));
- } else {
- movq(temp_reg, Immediate(reinterpret_cast<uword>(table_ptr)));
- movq(temp_reg, Address(temp_reg, 0));
- }
- } else {
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- movq(temp_reg, Address(temp_reg, table_offset));
- }
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ movq(temp_reg, Address(temp_reg, table_offset));
incq(Address(temp_reg, counter_offset));
}
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
ASSERT(cid < kNumPredefinedCids);
- UpdateAllocationStats(cid, space, inline_isolate);
+ UpdateAllocationStats(cid, space);
Register temp_reg = TMP;
intptr_t size_offset = ClassTable::SizeOffsetFor(cid, space == Heap::kNew);
addq(Address(temp_reg, size_offset), size_reg);
@@ -3529,11 +3501,10 @@
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
intptr_t size_in_bytes,
- Heap::Space space,
- bool inline_isolate) {
+ Heap::Space space) {
ASSERT(cid > 0);
ASSERT(cid < kNumPredefinedCids);
- UpdateAllocationStats(cid, space, inline_isolate);
+ UpdateAllocationStats(cid, space);
Register temp_reg = TMP;
intptr_t size_offset = ClassTable::SizeOffsetFor(cid, space == Heap::kNew);
addq(Address(temp_reg, size_offset), Immediate(size_in_bytes));
@@ -3550,8 +3521,7 @@
// 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,
- /* inline_isolate = */ false);
+ MaybeTraceAllocation(cls.id(), failure, near_jump);
const intptr_t instance_size = cls.instance_size();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
movq(temp, Address(THR, Thread::heap_offset()));
@@ -3563,7 +3533,7 @@
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
movq(Address(temp, Heap::TopOffset(space)), instance_reg);
- UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
+ UpdateAllocationStats(cls.id(), space);
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, Immediate(kHeapObjectTag - instance_size));
uword tags = 0;
@@ -3590,7 +3560,7 @@
// 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, /* inline_isolate = */ false);
+ MaybeTraceAllocation(cid, failure, near_jump);
Heap::Space space = Heap::SpaceForAllocation(cid);
movq(temp, Address(THR, Thread::heap_offset()));
movq(instance, Address(temp, Heap::TopOffset(space)));
@@ -3609,8 +3579,7 @@
// next object start and initialize the object.
movq(Address(temp, Heap::TopOffset(space)), end_address);
addq(instance, Immediate(kHeapObjectTag));
- UpdateAllocationStatsWithSize(cid, instance_size, space,
- /* inline_isolate = */ false);
+ UpdateAllocationStatsWithSize(cid, instance_size, space);
// Initialize the tags.
// instance: new object start as a tagged pointer.
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 4f6eac3..5f5aea4 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -975,24 +975,20 @@
void LeaveStubFrame();
void UpdateAllocationStats(intptr_t cid,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
- Heap::Space space,
- bool inline_isolate = true);
+ Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
intptr_t instance_size,
- Heap::Space space,
- bool inline_isolate = true);
+ 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,
- bool inline_isolate = true);
+ 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.
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 8ac98c2..2ba8dc1 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -337,11 +337,6 @@
}
-const char* BinaryOpWithMask32Node::TokenName() const {
- return Token::Str(kind());
-}
-
-
bool BinaryOpNode::IsPotentiallyConst() const {
switch (kind_) {
case Token::kOR:
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 4ca2372..13184af 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -24,7 +24,6 @@
V(Type) \
V(Assignable) \
V(BinaryOp) \
- V(BinaryOpWithMask32) \
V(Comparison) \
V(UnaryOp) \
V(ConditionalExpr) \
@@ -769,36 +768,6 @@
};
-class BinaryOpWithMask32Node : public BinaryOpNode {
- public:
- BinaryOpWithMask32Node(TokenPosition token_pos,
- Token::Kind kind_value,
- AstNode* left,
- AstNode* right,
- int64_t mask32)
- : BinaryOpNode(token_pos, kind_value, left, right), mask32_(mask32) {
- ASSERT(mask32 >= 0 && Utils::IsUint(32, mask32));
- ASSERT((kind_value != Token::kAND) && (kind_value != Token::kOR));
- }
-
- // The optional 32-bit mask must be a an unsigned 32-bit value.
- virtual bool has_mask32() const { return true; }
- virtual int64_t mask32() const {
- ASSERT(has_mask32());
- return mask32_;
- }
-
- const char* TokenName() const;
- DECLARE_COMMON_NODE_FUNCTIONS(BinaryOpWithMask32Node);
-
- private:
- // Optional unsigned 32 bit mask applied on result. No mask: -1.
- const int64_t mask32_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryOpWithMask32Node);
-};
-
-
class UnaryOpNode : public AstNode {
public:
// Returns optimized version, e.g., for ('-' '1') ('-1') literal is returned.
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index e438827..eb5dd3b 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -228,14 +228,6 @@
}
-void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
- THR_Print("(%s %s ", node->Name(), node->TokenName());
- node->VisitChildren(this);
- THR_Print(" & \"0x%" Px64 "", node->mask32());
- THR_Print("\")");
-}
-
-
void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
THR_Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index a81babb..28861ef 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -298,19 +298,6 @@
}
-void AwaitTransformer::VisitBinaryOpWithMask32Node(
- BinaryOpWithMask32Node* node) {
- ASSERT((node->kind() != Token::kAND) && (node->kind() != Token::kOR));
- AstNode* new_left = Transform(node->left());
- AstNode* new_right = Transform(node->right());
- result_ = MakeName(new(Z) BinaryOpWithMask32Node(node->token_pos(),
- node->kind(),
- new_left,
- new_right,
- node->mask32()));
-}
-
-
void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) {
AstNode* new_left = Transform(node->left());
AstNode* new_right = Transform(node->right());
diff --git a/runtime/vm/atomic.h b/runtime/vm/atomic.h
index 026762f..c182a84 100644
--- a/runtime/vm/atomic.h
+++ b/runtime/vm/atomic.h
@@ -65,9 +65,15 @@
} // namespace dart
+#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
+#define USING_SIMULATOR_ATOMICS
+#endif
+
+#if defined(USING_SIMULATOR_ATOMICS)
// We need to use the simulator to ensure that atomic operations are observed
// both in C++ and in generated code if the simulator is active.
#include "vm/atomic_simulator.h"
+#endif
#if defined(TARGET_OS_ANDROID)
#include "vm/atomic_android.h"
diff --git a/runtime/vm/atomic_android.h b/runtime/vm/atomic_android.h
index b994343..689173a 100644
--- a/runtime/vm/atomic_android.h
+++ b/runtime/vm/atomic_android.h
@@ -41,7 +41,7 @@
}
-#if !defined(USING_SIMULATOR)
+#if !defined(USING_SIMULATOR_ATOMICS)
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
@@ -54,7 +54,7 @@
uint32_t new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
-#endif // !defined(USING_SIMULATOR)
+#endif // !defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
diff --git a/runtime/vm/atomic_linux.h b/runtime/vm/atomic_linux.h
index 615004a..18456cf 100644
--- a/runtime/vm/atomic_linux.h
+++ b/runtime/vm/atomic_linux.h
@@ -27,7 +27,12 @@
inline void AtomicOperations::IncrementInt64By(int64_t* p, int64_t value) {
+#if defined(TARGET_ARCH_MIPS)
+ // No double-word atomics on MIPS32.
+ *p += value;
+#else
__sync_fetch_and_add(p, value);
+#endif
}
@@ -41,7 +46,7 @@
}
-#if !defined(USING_SIMULATOR)
+#if !defined(USING_SIMULATOR_ATOMICS)
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
@@ -54,7 +59,7 @@
uint32_t new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
-#endif // !defined(USING_SIMULATOR)
+#endif // !defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
diff --git a/runtime/vm/atomic_macos.h b/runtime/vm/atomic_macos.h
index ae5da3a..479ca30 100644
--- a/runtime/vm/atomic_macos.h
+++ b/runtime/vm/atomic_macos.h
@@ -41,7 +41,7 @@
}
-#if !defined(USING_SIMULATOR)
+#if !defined(USING_SIMULATOR_ATOMICS)
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
@@ -54,7 +54,7 @@
uint32_t new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
-#endif // !defined(USING_SIMULATOR)
+#endif // !defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
diff --git a/runtime/vm/atomic_simulator.h b/runtime/vm/atomic_simulator.h
index 2b52a22..78e7f88 100644
--- a/runtime/vm/atomic_simulator.h
+++ b/runtime/vm/atomic_simulator.h
@@ -11,7 +11,7 @@
namespace dart {
-#if defined(USING_SIMULATOR)
+#if defined(USING_SIMULATOR_ATOMICS)
// Forward atomic operations to the simulator if the simulator is active.
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
@@ -25,7 +25,7 @@
uint32_t new_value) {
return Simulator::CompareExchangeUint32(ptr, old_value, new_value);
}
-#endif // defined(USING_SIMULATOR)
+#endif // defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 7750375..d4fb651 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -526,8 +526,8 @@
// Write snapshot with object content.
FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
&isolate_snapshot_buffer,
- NULL, /* instructions_snapshot_buffer */
&malloc_allocator,
+ NULL, /* instructions_writer */
false, /* snapshot_code */
true /* vm_isolate_is_symbolic */);
writer.WriteFullSnapshot();
@@ -563,8 +563,8 @@
// Write snapshot with object content.
FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
&isolate_snapshot_buffer,
- NULL, /* instructions_snapshot_buffer */
&malloc_allocator,
+ NULL, /* instructions_writer */
false, /* snapshot_code */
true /* vm_isolate_is_symbolic */);
writer.WriteFullSnapshot();
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 777f1f9..81d46ec 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -45,7 +45,6 @@
V(Integer_equalToInteger, 2) \
V(Integer_fromEnvironment, 3) \
V(Integer_parse, 1) \
- V(Integer_leftShiftWithMask32, 3) \
V(Bool_fromEnvironment, 3) \
V(CapabilityImpl_factory, 1) \
V(CapabilityImpl_equals, 2) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 1db0305..81cd85c 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -993,13 +993,16 @@
!(type_arg.Equals(type_param) &&
instantiated_bound.Equals(declared_bound))) {
// If type_arg is a type parameter, its declared bound may not be
- // resolved yet.
+ // finalized yet.
if (type_arg.IsTypeParameter()) {
const Class& type_arg_cls = Class::Handle(
TypeParameter::Cast(type_arg).parameterized_class());
AbstractType& bound = AbstractType::Handle(
TypeParameter::Cast(type_arg).bound());
- ResolveType(type_arg_cls, bound);
+ if (!bound.IsFinalized() && !bound.IsBeingFinalized()) {
+ bound = FinalizeType(type_arg_cls, bound, kCanonicalize);
+ TypeParameter::Cast(type_arg).set_bound(bound);
+ }
}
// This may be called only if type needs to be finalized, therefore
// seems OK to allocate finalized types in old space.
@@ -2516,20 +2519,22 @@
// values field. We also don't have to generate the code for these getters
// from thin air (no source code is available).
void ClassFinalizer::AllocateEnumValues(const Class &enum_cls) {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
const Field& index_field =
- Field::Handle(enum_cls.LookupInstanceField(Symbols::Index()));
+ Field::Handle(zone, enum_cls.LookupInstanceField(Symbols::Index()));
ASSERT(!index_field.IsNull());
const Field& values_field =
- Field::Handle(enum_cls.LookupStaticField(Symbols::Values()));
+ Field::Handle(zone, enum_cls.LookupStaticField(Symbols::Values()));
ASSERT(!values_field.IsNull());
- ASSERT(Instance::Handle(values_field.StaticValue()).IsArray());
+ ASSERT(Instance::Handle(zone, values_field.StaticValue()).IsArray());
Array& values_list = Array::Handle(
- Array::RawCast(values_field.StaticValue()));
+ zone, Array::RawCast(values_field.StaticValue()));
- const Array& fields = Array::Handle(enum_cls.fields());
- Field& field = Field::Handle();
- Instance& ordinal_value = Instance::Handle();
- Instance& enum_value = Instance::Handle();
+ const Array& fields = Array::Handle(zone, enum_cls.fields());
+ Field& field = Field::Handle(zone);
+ Instance& ordinal_value = Instance::Handle(zone);
+ Instance& enum_value = Instance::Handle(zone);
for (intptr_t i = 0; i < fields.Length(); i++) {
field = Field::RawCast(fields.At(i));
@@ -2542,7 +2547,7 @@
enum_value = Instance::New(enum_cls, Heap::kOld);
enum_value.SetField(index_field, ordinal_value);
const char* error_msg = "";
- enum_value = enum_value.CheckAndCanonicalize(&error_msg);
+ enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
ASSERT(!enum_value.IsNull());
ASSERT(enum_value.IsCanonical());
field.SetStaticValue(enum_value, true);
@@ -2553,7 +2558,7 @@
}
values_list.MakeImmutable();
const char* error_msg = NULL;
- values_list ^= values_list.CheckAndCanonicalize(&error_msg);
+ values_list ^= values_list.CheckAndCanonicalize(thread, &error_msg);
ASSERT(!values_list.IsNull());
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 1aa9dda..97b8fc8 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -31,16 +31,11 @@
"Maximum number of subtype cache entries (number of checks cached).");
DEFINE_FLAG(int, regexp_optimization_counter_threshold, 1000,
"RegExp's usage-counter value before it is optimized, -1 means never");
-DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function");
DEFINE_FLAG(int, reoptimization_counter_threshold, 4000,
"Counter threshold before a function gets reoptimized.");
-DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false,
- "Debugging: stops program if deoptimizing same function too often");
DEFINE_FLAG(bool, trace_deoptimization, false, "Trace deoptimization");
DEFINE_FLAG(bool, trace_deoptimization_verbose, false,
"Trace deoptimization verbose");
-DEFINE_FLAG(bool, trace_failed_optimization_attempts, false,
- "Traces all failed optimization attempts");
DEFINE_FLAG(bool, trace_ic, false, "Trace IC handling");
DEFINE_FLAG(bool, trace_ic_miss_in_optimized, false,
"Trace IC miss in optimized code");
@@ -659,6 +654,7 @@
}
+#if !defined(TARGET_ARCH_DBC)
// Gets called from debug stub when code reaches a breakpoint
// set on a runtime stub call.
DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
@@ -679,6 +675,20 @@
}
arguments.SetReturn(orig_stub);
}
+#else
+// Gets called from the simulator when the breakpoint is reached.
+DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
+ if (!FLAG_support_debugger) {
+ UNREACHABLE();
+ return;
+ }
+ const Error& error = Error::Handle(isolate->debugger()->SignalBpReached());
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ UNREACHABLE();
+ }
+}
+#endif // !defined(TARGET_ARCH_DBC)
DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
@@ -961,6 +971,8 @@
// Arg2: Arguments descriptor array.
// Returns: target function to call.
DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
+// DBC does not use megamorphic calls right now.
+#if !defined(TARGET_ARCH_DBC)
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1));
const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2));
@@ -1018,6 +1030,9 @@
cache.Insert(class_id, target_function);
}
arguments.SetReturn(target_function);
+#else
+ UNREACHABLE();
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -1195,72 +1210,9 @@
}
-static bool CanOptimizeFunction(const Function& function, Thread* thread) {
- if (FLAG_support_debugger) {
- Isolate* isolate = thread->isolate();
- if (isolate->debugger()->IsStepping() ||
- isolate->debugger()->HasBreakpoint(function, thread->zone())) {
- // We cannot set breakpoints and single step in optimized code,
- // so do not optimize the function.
- function.set_usage_counter(0);
- return false;
- }
- }
- if (function.deoptimization_counter() >=
- FLAG_max_deoptimization_counter_threshold) {
- if (FLAG_trace_failed_optimization_attempts ||
- FLAG_stop_on_excessive_deoptimization) {
- THR_Print("Too many deoptimizations: %s\n",
- function.ToFullyQualifiedCString());
- if (FLAG_stop_on_excessive_deoptimization) {
- FATAL("Stop on excessive deoptimization");
- }
- }
- // The function will not be optimized any longer. This situation can occur
- // mostly with small optimization counter thresholds.
- function.SetIsOptimizable(false);
- function.set_usage_counter(INT_MIN);
- return false;
- }
- if (FLAG_optimization_filter != NULL) {
- // FLAG_optimization_filter is a comma-separated list of strings that are
- // matched against the fully-qualified function name.
- char* save_ptr; // Needed for strtok_r.
- const char* function_name = function.ToFullyQualifiedCString();
- intptr_t len = strlen(FLAG_optimization_filter) + 1; // Length with \0.
- char* filter = new char[len];
- strncpy(filter, FLAG_optimization_filter, len); // strtok modifies arg 1.
- char* token = strtok_r(filter, ",", &save_ptr);
- bool found = false;
- while (token != NULL) {
- if (strstr(function_name, token) != NULL) {
- found = true;
- break;
- }
- token = strtok_r(NULL, ",", &save_ptr);
- }
- delete[] filter;
- if (!found) {
- function.set_usage_counter(INT_MIN);
- return false;
- }
- }
- if (!function.IsOptimizable()) {
- // Huge methods (code size above --huge_method_cutoff_in_code_size) become
- // non-optimizable only after the code has been generated.
- if (FLAG_trace_failed_optimization_attempts) {
- THR_Print("Not optimizable: %s\n", function.ToFullyQualifiedCString());
- }
- function.set_usage_counter(INT_MIN);
- return false;
- }
- return true;
-}
-
-
DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
#if defined(USING_SIMULATOR)
- uword stack_pos = Simulator::Current()->get_register(SPREG);
+ uword stack_pos = Simulator::Current()->get_sp();
#else
uword stack_pos = Thread::GetCurrentStackPointer();
#endif
@@ -1272,7 +1224,7 @@
// If an interrupt happens at the same time as a stack overflow, we
// process the stack overflow now and leave the interrupt for next
// time.
- if (stack_pos < thread->saved_stack_limit()) {
+ if (IsCalleeFrameOf(thread->saved_stack_limit(), stack_pos)) {
// Use the preallocated stack overflow exception to avoid calling
// into dart code.
const Instance& exception =
@@ -1364,7 +1316,8 @@
ASSERT(function.HasCode());
// Don't do OSR on intrinsified functions: The intrinsic code expects to be
// called like a regular function and can't be entered via OSR.
- if (!CanOptimizeFunction(function, thread) || function.is_intrinsic()) {
+ if (!Compiler::CanOptimizeFunction(thread, function) ||
+ function.is_intrinsic()) {
return;
}
@@ -1434,7 +1387,7 @@
ASSERT(!function.IsNull());
ASSERT(function.HasCode());
- if (CanOptimizeFunction(function, thread)) {
+ if (Compiler::CanOptimizeFunction(thread, function)) {
if (FLAG_background_compilation) {
Field& field = Field::Handle(zone, isolate->GetDeoptimizingBoxedField());
while (!field.IsNull()) {
@@ -1452,6 +1405,9 @@
if (FLAG_enable_inlining_annotations) {
FATAL("Cannot enable inlining annotations and background compilation");
}
+ if (FLAG_background_compilation_stop_alot) {
+ BackgroundCompiler::Stop(isolate);
+ }
// Reduce the chance of triggering optimization while the function is
// being optimized in the background. INT_MIN should ensure that it takes
// long time to trigger optimization.
diff --git a/runtime/vm/code_patcher_dbc.cc b/runtime/vm/code_patcher_dbc.cc
new file mode 100644
index 0000000..e0010ab
--- /dev/null
+++ b/runtime/vm/code_patcher_dbc.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/code_patcher.h"
+
+#include "vm/flow_graph_compiler.h"
+#include "vm/instructions.h"
+#include "vm/object.h"
+
+namespace dart {
+
+RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address,
+ const Code& code) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ CallPattern call(return_address, code);
+ return call.TargetCode();
+}
+
+
+void CodePatcher::PatchStaticCallAt(uword return_address,
+ const Code& code,
+ const Code& new_target) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ CallPattern call(return_address, code);
+ call.SetTargetCode(new_target);
+}
+
+
+void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) {
+ // The inserted call should not overlap the lazy deopt jump code.
+ ASSERT(start + CallPattern::DeoptCallPatternLengthInBytes() <= target);
+ CallPattern::InsertDeoptCallAt(start, target);
+}
+
+
+RawCode* CodePatcher::GetInstanceCallAt(uword return_address,
+ const Code& code,
+ ICData* ic_data) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ CallPattern call(return_address, code);
+ if (ic_data != NULL) {
+ *ic_data = call.IcData();
+ }
+ return call.TargetCode();
+}
+
+
+intptr_t CodePatcher::InstanceCallSizeInBytes() {
+ UNREACHABLE();
+ return 0;
+}
+
+
+RawFunction* CodePatcher::GetUnoptimizedStaticCallAt(
+ uword return_address, const Code& code, ICData* ic_data_result) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ CallPattern static_call(return_address, code);
+ ICData& ic_data = ICData::Handle();
+ ic_data ^= static_call.IcData();
+ if (ic_data_result != NULL) {
+ *ic_data_result = ic_data.raw();
+ }
+ return ic_data.GetTargetAt(0);
+}
+
+
+void CodePatcher::PatchSwitchableCallAt(uword return_address,
+ const Code& code,
+ const ICData& ic_data,
+ const MegamorphicCache& cache,
+ const Code& lookup_stub) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ SwitchableCallPattern call(return_address, code);
+ ASSERT(call.cache() == ic_data.raw());
+ call.SetLookupStub(lookup_stub);
+ call.SetCache(cache);
+}
+
+
+void CodePatcher::PatchNativeCallAt(uword return_address,
+ const Code& code,
+ NativeFunction target,
+ const Code& trampoline) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ NativeCallPattern call(return_address, code);
+ call.set_target(trampoline);
+ call.set_native_function(target);
+}
+
+
+RawCode* CodePatcher::GetNativeCallAt(uword return_address,
+ const Code& code,
+ NativeFunction* target) {
+ ASSERT(code.ContainsInstructionAt(return_address));
+ NativeCallPattern call(return_address, code);
+ *target = call.native_function();
+ return call.target();
+}
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index 2e6ec02..b8863dc 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -35,6 +35,12 @@
}
+intptr_t IndexFromPPLoadDisp8(uword start) {
+ int8_t offset = *reinterpret_cast<int8_t*>(start);
+ return ObjectPool::IndexFromOffset(offset);
+}
+
+
class UnoptimizedCall : public ValueObject {
public:
UnoptimizedCall(uword return_address, const Code& code)
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index fd0e748..55afac1 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -55,6 +55,7 @@
"How many times we allow deoptimization before we disallow optimization.");
DEFINE_FLAG(bool, loop_invariant_code_motion, true,
"Do loop invariant code motion.");
+DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function");
DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph.");
DEFINE_FLAG(bool, print_flow_graph_optimized, false,
"Print the IR flow graph when optimizing.");
@@ -62,7 +63,13 @@
"Print the deopt-id to ICData map in optimizing compiler.");
DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map.");
DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis");
+DEFINE_FLAG(bool, stress_test_background_compilation, false,
+ "Keep background compiler running all the time");
+DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false,
+ "Debugging: stops program if deoptimizing same function too often");
DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations.");
+DEFINE_FLAG(bool, trace_failed_optimization_attempts, false,
+ "Traces all failed optimization attempts");
DEFINE_FLAG(bool, trace_optimizing_compiler, false,
"Trace only optimizing compiler operations.");
DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler.");
@@ -163,6 +170,69 @@
}
+bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) {
+ if (FLAG_support_debugger) {
+ Isolate* isolate = thread->isolate();
+ if (isolate->debugger()->IsStepping() ||
+ isolate->debugger()->HasBreakpoint(function, thread->zone())) {
+ // We cannot set breakpoints and single step in optimized code,
+ // so do not optimize the function.
+ function.set_usage_counter(0);
+ return false;
+ }
+ }
+ if (function.deoptimization_counter() >=
+ FLAG_max_deoptimization_counter_threshold) {
+ if (FLAG_trace_failed_optimization_attempts ||
+ FLAG_stop_on_excessive_deoptimization) {
+ THR_Print("Too many deoptimizations: %s\n",
+ function.ToFullyQualifiedCString());
+ if (FLAG_stop_on_excessive_deoptimization) {
+ FATAL("Stop on excessive deoptimization");
+ }
+ }
+ // The function will not be optimized any longer. This situation can occur
+ // mostly with small optimization counter thresholds.
+ function.SetIsOptimizable(false);
+ function.set_usage_counter(INT_MIN);
+ return false;
+ }
+ if (FLAG_optimization_filter != NULL) {
+ // FLAG_optimization_filter is a comma-separated list of strings that are
+ // matched against the fully-qualified function name.
+ char* save_ptr; // Needed for strtok_r.
+ const char* function_name = function.ToFullyQualifiedCString();
+ intptr_t len = strlen(FLAG_optimization_filter) + 1; // Length with \0.
+ char* filter = new char[len];
+ strncpy(filter, FLAG_optimization_filter, len); // strtok modifies arg 1.
+ char* token = strtok_r(filter, ",", &save_ptr);
+ bool found = false;
+ while (token != NULL) {
+ if (strstr(function_name, token) != NULL) {
+ found = true;
+ break;
+ }
+ token = strtok_r(NULL, ",", &save_ptr);
+ }
+ delete[] filter;
+ if (!found) {
+ function.set_usage_counter(INT_MIN);
+ return false;
+ }
+ }
+ if (!function.IsOptimizable()) {
+ // Huge methods (code size above --huge_method_cutoff_in_code_size) become
+ // non-optimizable only after the code has been generated.
+ if (FLAG_trace_failed_optimization_attempts) {
+ THR_Print("Not optimizable: %s\n", function.ToFullyQualifiedCString());
+ }
+ function.set_usage_counter(INT_MIN);
+ return false;
+ }
+ return true;
+}
+
+
bool Compiler::IsBackgroundCompilation() {
// For now: compilation in non mutator thread is the background compoilation.
return !Thread::Current()->IsMutatorThread();
@@ -403,6 +473,7 @@
void FinalizeCompilation(Assembler* assembler,
FlowGraphCompiler* graph_compiler,
FlowGraph* flow_graph);
+ void CheckIfBackgroundCompilerIsBeingStopped();
ParsedFunction* parsed_function_;
const bool optimized_;
@@ -542,7 +613,8 @@
THR_Print("--> FAIL: Loading invalidation.");
}
}
- if (code_is_valid) {
+ // Setting breakpoints at runtime could make a function non-optimizable.
+ if (code_is_valid && Compiler::CanOptimizeFunction(thread(), function)) {
const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId;
ASSERT(!is_osr); // OSR is not compiled in background.
function.InstallOptimizedCode(code, is_osr);
@@ -595,6 +667,16 @@
}
+void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped() {
+ ASSERT(Compiler::IsBackgroundCompilation());
+ if (!isolate()->background_compiler()->is_running()) {
+ // The background compiler is being stopped.
+ Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId,
+ "Background compilation is being stopped");
+ }
+}
+
+
// Return false if bailed out.
// If optimized_result_code is not NULL then it is caller's responsibility
// to install code.
@@ -1062,20 +1144,20 @@
// changes code page access permissions (makes them temporary not
// executable).
{
+ CheckIfBackgroundCompilerIsBeingStopped();
SafepointOperationScope safepoint_scope(thread());
// Do not Garbage collect during this stage and instead allow the
// heap to grow.
NoHeapGrowthControlScope no_growth_control;
- if (!isolate()->background_compiler()->is_running()) {
- // The background compiler is being stopped.
- Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId,
- "Background compilation is being stopped");
- }
+ CheckIfBackgroundCompilerIsBeingStopped();
FinalizeCompilation(&assembler, &graph_compiler, flow_graph);
}
- if (isolate()->heap()->NeedsGarbageCollection()) {
- isolate()->heap()->CollectAllGarbage();
- }
+ // TODO(srdjan): Enable this and remove the one from
+ // 'BackgroundCompiler::CompileOptimized' once cause of time-outs
+ // is resolved.
+ // if (isolate()->heap()->NeedsGarbageCollection()) {
+ // isolate()->heap()->CollectAllGarbage();
+ // }
}
}
// Mark that this isolate now has compiled code.
@@ -1586,6 +1668,7 @@
if (FLAG_trace_compiler) {
THR_Print("ABORT background compilation: %s\n", msg);
}
+NOT_IN_PRODUCT(
TimelineStream* stream = Timeline::GetCompilerStream();
ASSERT(stream != NULL);
TimelineEvent* event = stream->StartEvent();
@@ -1595,6 +1678,7 @@
event->CopyArgument(0, "reason", msg);
event->Complete();
}
+) // !PRODUCT
ASSERT(Compiler::IsBackgroundCompilation());
Thread::Current()->long_jump_base()->Jump(
deopt_id, Object::background_compilation_error());
@@ -1607,7 +1691,6 @@
explicit QueueElement(const Function& function)
: next_(NULL),
function_(function.raw()) {
- ASSERT(Thread::Current()->IsMutatorThread());
}
virtual ~QueueElement() {
@@ -1752,7 +1835,7 @@
{ MonitorLocker ml(queue_monitor_);
function = function_queue()->PeekFunction();
}
- while (running_ && !function.IsNull()) {
+ while (running_ && !function.IsNull() && !isolate_->IsTopLevelParsing()) {
// Check that we have aggregated and cleared the stats.
ASSERT(thread->compiler_stats()->IsCleared());
const Error& error = Error::Handle(zone,
@@ -1780,6 +1863,13 @@
function = Function::null();
} else {
qelem = function_queue()->Remove();
+ if (FLAG_stress_test_background_compilation) {
+ const Function& old = Function::Handle(qelem->Function());
+ if (Compiler::CanOptimizeFunction(thread, old)) {
+ QueueElement* repeat_qelem = new QueueElement(old);
+ function_queue()->Add(repeat_qelem);
+ }
+ }
function = function_queue()->PeekFunction();
}
}
@@ -1792,7 +1882,8 @@
{
// Wait to be notified when the work queue is not empty.
MonitorLocker ml(queue_monitor_);
- while (function_queue()->IsEmpty() && running_) {
+ while ((function_queue()->IsEmpty() || isolate_->IsTopLevelParsing())
+ && running_) {
ml.Wait();
}
}
@@ -1809,14 +1900,21 @@
void BackgroundCompiler::CompileOptimized(const Function& function) {
ASSERT(Thread::Current()->IsMutatorThread());
- MonitorLocker ml(queue_monitor_);
- ASSERT(running_);
- if (function_queue()->ContainsObj(function)) {
- return;
+ // TODO(srdjan): Checking different strategy for collecting garbage
+ // accumulated by background compiler.
+ if (isolate_->heap()->NeedsGarbageCollection()) {
+ isolate_->heap()->CollectAllGarbage();
}
- QueueElement* elem = new QueueElement(function);
- function_queue()->Add(elem);
- ml.Notify();
+ {
+ MonitorLocker ml(queue_monitor_);
+ ASSERT(running_);
+ if (function_queue()->ContainsObj(function)) {
+ return;
+ }
+ QueueElement* elem = new QueueElement(function);
+ function_queue()->Add(elem);
+ ml.Notify();
+ }
}
@@ -1827,7 +1925,10 @@
void BackgroundCompiler::Stop(Isolate* isolate) {
BackgroundCompiler* task = isolate->background_compiler();
- ASSERT(task != NULL);
+ if (task == NULL) {
+ // Nothing to stop.
+ return;
+ }
BackgroundCompilationQueue* function_queue = task->function_queue();
Monitor* queue_monitor = task->queue_monitor_;
@@ -1908,6 +2009,11 @@
bool Compiler::IsBackgroundCompilation() {
+ return false;
+}
+
+
+bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) {
UNREACHABLE();
return false;
}
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 2f2eb1c..4e2a550 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -81,6 +81,8 @@
static const intptr_t kNoOSRDeoptId = Thread::kNoDeoptId;
static bool IsBackgroundCompilation();
+ // The result for a function may change if debugging gets turned on/off.
+ static bool CanOptimizeFunction(Thread* thread, const Function& function);
// Extracts top level entities from the script and populates
// the class dictionary of the library.
@@ -146,8 +148,7 @@
// because the mutator thread changed the state (e.g., deoptimization,
// deferred loading). The background compilation may retry to compile
// the same function later.
- static void AbortBackgroundCompilation(intptr_t deopt_id,
- const char* msg = "");
+ static void AbortBackgroundCompilation(intptr_t deopt_id, const char* msg);
};
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index b8e7c2a..0b8d617 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -533,6 +533,7 @@
void ConstantPropagator::VisitTestCids(TestCidsInstr* instr) {
+ // TODO(sra): Constant fold test.
SetValue(instr, non_constant_);
}
diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h
new file mode 100644
index 0000000..4eb7b1b
--- /dev/null
+++ b/runtime/vm/constants_dbc.h
@@ -0,0 +1,494 @@
+// Copyright (c) 2016, 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_CONSTANTS_DBC_H_
+#define VM_CONSTANTS_DBC_H_
+
+#include "platform/globals.h"
+#include "platform/assert.h"
+#include "platform/utils.h"
+
+
+namespace dart {
+
+// List of Dart Bytecode instructions.
+//
+// INTERPRETER STATE
+//
+// current frame info (see stack_frame_dbc.h for layout)
+// v-----^-----v
+// ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~
+// ~ | ~ ~ | FP[0] | FP[1] | ~ ~ | SP[-1]| SP[0] |
+// ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~
+// ^ ^
+// FP SP
+//
+//
+// The state of execution is captured in few interpreter registers:
+//
+// FP - base of the current frame
+// SP - top of the stack (TOS) for the current frame
+// PP - object pool for the currently execution function
+//
+// Frame info stored below FP additionally contains pointers to the currently
+// executing function and code (see stack_frame_dbc.h for more information).
+//
+// In the unoptimized code most of bytecodes take operands implicitly from
+// stack and store results again on the stack. Constant operands are usually
+// taken from the object pool by index.
+//
+// ENCODING
+//
+// Each instruction is a 32-bit integer with opcode stored in the least
+// significant byte. The following operand encodings are used:
+//
+// 0........8.......16.......24.......32
+// +--------+--------+--------+--------+
+// | opcode |~~~~~~~~~~~~~~~~~~~~~~~~~~| 0: no operands
+// +--------+--------+--------+--------+
+//
+// +--------+--------+--------+--------+
+// | opcode | A |~~~~~~~~~~~~~~~~~| A: single unsigned 8-bit operand
+// +--------+--------+--------+--------+
+//
+// +--------+--------+--------+--------+
+// | opcode | A | D | A_D: unsigned 8-bit operand and
+// +--------+--------+--------+--------+ unsigned 16-bit operand
+//
+// +--------+--------+--------+--------+
+// | opcode | A | X | A_X: unsigned 8-bit operand and
+// +--------+--------+--------+--------+ signed 16-bit operand
+//
+// +--------+--------+--------+--------+
+// | opcode |~~~~~~~~| D | D: unsigned 16-bit operand
+// +--------+--------+--------+--------+
+//
+// +--------+--------+--------+--------+
+// | opcode |~~~~~~~~| X | X: signed 16-bit operand
+// +--------+--------+--------+--------+
+//
+// +--------+--------+--------+--------+
+// | opcode | A | B | C | A_B_C: 3 unsigned 8-bit operands
+// +--------+--------+--------+--------+
+//
+// +--------+--------+--------+--------+
+// | opcode | T | T: signed 24-bit operand
+// +--------+--------+--------+--------+
+//
+//
+// INSTRUCTIONS
+//
+// - Trap
+//
+// Unreachable instruction.
+//
+// - Compile
+//
+// Compile current function and start executing newly produced code
+// (used to implement LazyCompileStub);
+//
+// - Intrinsic id
+//
+// Execute intrinsic with the given id. If intrinsic returns true then
+// return from the current function to the caller passing value produced
+// by the intrinsic as a result;
+//
+// - Drop1; DropR n; Drop n
+//
+// Drop 1 or n values from the stack, if instruction is DropR push the first
+// dropped value to the stack;
+//
+// - Jump target
+//
+// Jump to the given target. Target is specified as offset from the PC of the
+// jump instruction.
+//
+// - Return R; ReturnTOS
+//
+// Return to the caller using either a value from the given register or a
+// value from the top-of-stack as a result.
+//
+// Note: return instruction knows how many arguments to remove from the
+// stack because it can look at the call instruction at caller's PC and
+// take argument count from it.
+//
+// - Move rA, rX
+//
+// FP[rA] <- FP[rX]
+// Note: rX is signed so it can be used to address parameters which are
+// at negative indices with respect to FP.
+//
+// - Push rX
+//
+// Push FP[rX] to the stack.
+//
+// - LoadConstant rA, D; PushConstant D
+//
+// Load value at index D from constant pool into FP[rA] or push it onto the
+// stack.
+//
+// - StoreLocal rX; PopLocal rX
+//
+// Store top of the stack into FP[rX] and pop it if needed.
+//
+// - StaticCall ArgC, D
+//
+// Invoke function in SP[0] with arguments SP[-(1+ArgC)], ..., SP[-1] and
+// argument descriptor PP[D].
+//
+// - InstanceCall ArgC, D; InstanceCall2 ArgC, D; InstanceCall3 ArgC, D
+//
+// Lookup and invoke method using ICData in PP[D] with arguments
+// SP[-(1+ArgC)], ..., SP[-1].
+//
+// - NativeCall, NativeBootstrapCall
+//
+// Invoke native function SP[-1] with argc_tag SP[0].
+//
+// - AddTOS; SubTOS; MulTOS; BitOrTOS; BitAndTOS; EqualTOS; LessThanTOS;
+// GreaterThanTOS;
+//
+// Smi fast-path for a corresponding method. Checks if SP[0] and SP[-1] are
+// both smis and result of SP[0] <op> SP[-1] is a smi - if this is true
+// then pops operands and pushes result on the stack and skips the next
+// instruction (which implements a slow path fallback).
+//
+// - StoreStaticTOS D
+//
+// Stores TOS into the static field PP[D].
+//
+// - PushStatic
+//
+// Pushes value of the static field PP[D] on to the stack.
+//
+// - InitStaticTOS
+//
+// Takes static field from TOS and ensures that it is initialized.
+//
+// - IfNeStrictTOS; IfEqStrictTOS; IfNeStrictNumTOS; IfEqStrictNumTOS
+//
+// Skips the next instruction unless the given condition holds. 'Num'
+// variants perform number check while non-Num variants just compare
+// RawObject pointers.
+//
+// Used to implement conditional jump:
+//
+// IfNeStrictTOS
+// Jump T ;; jump if not equal
+//
+// - CreateArrayTOS
+//
+// Allocate array of length SP[0] with type arguments SP[-1].
+//
+// - Allocate D
+//
+// Allocate object of class PP[D] with no type arguments.
+//
+// - AllocateT
+//
+// Allocate object of class SP[0] with type arguments SP[-1].
+//
+// - StoreIndexedTOS
+//
+// Store SP[0] into array SP[-2] at index SP[-1]. No typechecking is done.
+// SP[-2] is assumed to be a RawArray, SP[-1] to be a smi.
+//
+// - StoreField rA, B, rC
+//
+// Store value FP[rC] into object FP[rA] at offset (in words) B.
+//
+// - StoreFieldTOS D
+//
+// Store value SP[0] into object SP[-1] at offset (in words) D.
+//
+// - LoadField rA, rB, C
+//
+// Load value at offset (in words) C from object FP[rB] into FP[rA].
+//
+// - LoadFieldTOS D
+//
+// Push value at offset (in words) D from object SP[0].
+//
+// - BooleanNegateTOS
+//
+// SP[0] = !SP[0]
+//
+// - Throw A
+//
+// Throw (Rethrow if A != 0) exception. Exception object and stack object
+// are taken from TOS.
+//
+// - Entry A, B, rC
+//
+// Function prologue for the function with no optional or named arguments:
+// A - expected number of positional arguments;
+// B - number of local slots to reserve;
+// rC - specifies context register to initialize with empty context.
+//
+// - EntryOpt A, B, C
+//
+// Function prologue for the function with optional or named arguments:
+// A - expected number of positional arguments;
+// B - number of optional arguments;
+// C - number of named arguments;
+//
+// Only one of B and C can be not 0.
+//
+// If B is not 0 then EntryOpt bytecode is followed by B LoadConstant
+// bytecodes specifying default values for optional arguments.
+//
+// If C is not 0 then EntryOpt is followed by 2 * B LoadConstant bytecodes.
+// Bytecode at 2 * i specifies name of the i-th named argument and at
+// 2 * i + 1 default value. rA part of the LoadConstant bytecode specifies
+// the location of the parameter on the stack. Here named arguments are
+// sorted alphabetically to enable linear matching similar to how function
+// prologues are implemented on other architectures.
+//
+// Note: Unlike Entry bytecode EntryOpt does not setup the frame for
+// local variables this is done by a separate bytecode Frame.
+//
+// - Frame D
+//
+// Reserve and initialize with null space for D local variables.
+//
+// - SetFrame A
+//
+// Reinitialize SP assuming that current frame has size A.
+// Used to drop temporaries from the stack in the exception handler.
+//
+// - AllocateContext D
+//
+// Allocate Context object assuming for D context variables.
+//
+// - CloneContext
+//
+// Clone context stored in TOS.
+//
+// - MoveSpecial rA, D
+//
+// Copy special values from inside interpreter to FP[rA]. Currently only
+// used to pass exception object (D = 0) and stack trace object (D = 1) to
+// catch handler.
+//
+// - InstantiateType D
+//
+// Instantiate type PP[D] with instantiator type arguments SP[0].
+//
+// - InstantiateTypeArgumentsTOS D
+//
+// Instantiate type arguments PP[D] with instantiator SP[0].
+//
+// - AssertAssignable D
+//
+// Assert that SP[-3] is assignable to variable named SP[0] of type
+// SP[-1] with type arguments SP[-2] using SubtypeTestCache PP[D].
+//
+// - AssertBoolean A
+//
+// Assert that TOS is a boolean (A = 1) or that TOS is not null (A = 0).
+//
+// - CheckStack
+//
+// Compare SP against isolate stack limit and call StackOverflow handler if
+// necessary.
+//
+// - DebugStep, DebugBreak A
+//
+// Debugger support. DebugBreak is bytecode that can be patched into the
+// instruction stream to trigger in place breakpoint.
+//
+// When patching instance or static call with DebugBreak we set A to
+// match patched call's argument count so that Return instructions continue
+// to work.
+//
+// TODO(vegorov) the way we replace calls with DebugBreak does not work
+// with our smi fast paths because DebugBreak is simply skipped.
+//
+// BYTECODE LIST FORMAT
+//
+// Bytecode list below is specified using the following format:
+//
+// V(BytecodeName, OperandForm, Op1, Op2, Op3)
+//
+// - OperandForm specifies operand encoding and should be one of 0, A, T, A_D,
+// A_X, X, D (see ENCODING section above).
+//
+// - Op1, Op2, Op2 specify operand meaning. Possible values:
+//
+// ___ ignored / non-existent operand
+// num immediate operand
+// lit constant literal from object pool
+// reg register (unsigned FP relative local)
+// xeg x-register (signed FP relative local)
+// tgt jump target relative to the PC of the current instruction
+//
+// TODO(vegorov) jump targets should be encoded relative to PC of the next
+// instruction because PC is incremeted immediately after fetch
+// and before decoding.
+//
+#define BYTECODES_LIST(V) \
+ V(Trap, 0, ___, ___, ___) \
+ V(Compile, 0, ___, ___, ___) \
+ V(Intrinsic, A, num, ___, ___) \
+ V(Drop1, 0, ___, ___, ___) \
+ V(DropR, A, num, ___, ___) \
+ V(Drop, A, num, ___, ___) \
+ V(Jump, T, tgt, ___, ___) \
+ V(Return, A, num, ___, ___) \
+ V(ReturnTOS, 0, ___, ___, ___) \
+ V(Move, A_X, reg, xeg, ___) \
+ V(Push, X, xeg, ___, ___) \
+ V(LoadConstant, A_D, reg, lit, ___) \
+ V(PushConstant, D, lit, ___, ___) \
+ V(StoreLocal, X, xeg, ___, ___) \
+ V(PopLocal, X, xeg, ___, ___) \
+ V(StaticCall, A_D, num, num, ___) \
+ V(InstanceCall, A_D, num, num, ___) \
+ V(InstanceCall2, A_D, num, num, ___) \
+ V(InstanceCall3, A_D, num, num, ___) \
+ V(NativeCall, 0, ___, ___, ___) \
+ V(NativeBootstrapCall, 0, ___, ___, ___) \
+ V(AddTOS, 0, ___, ___, ___) \
+ V(SubTOS, 0, ___, ___, ___) \
+ V(MulTOS, 0, ___, ___, ___) \
+ V(BitOrTOS, 0, ___, ___, ___) \
+ V(BitAndTOS, 0, ___, ___, ___) \
+ V(EqualTOS, 0, ___, ___, ___) \
+ V(LessThanTOS, 0, ___, ___, ___) \
+ V(GreaterThanTOS, 0, ___, ___, ___) \
+ V(StoreStaticTOS, D, lit, ___, ___) \
+ V(PushStatic, D, lit, ___, ___) \
+ V(InitStaticTOS, 0, ___, ___, ___) \
+ V(IfNeStrictTOS, 0, ___, ___, ___) \
+ V(IfEqStrictTOS, 0, ___, ___, ___) \
+ V(IfNeStrictNumTOS, 0, ___, ___, ___) \
+ V(IfEqStrictNumTOS, 0, ___, ___, ___) \
+ V(CreateArrayTOS, 0, ___, ___, ___) \
+ V(Allocate, D, lit, ___, ___) \
+ V(AllocateT, 0, ___, ___, ___) \
+ V(StoreIndexedTOS, 0, ___, ___, ___) \
+ V(StoreField, A_B_C, reg, reg, reg) \
+ V(StoreFieldTOS, D, num, ___, ___) \
+ V(LoadField, A_B_C, reg, reg, reg) \
+ V(LoadFieldTOS, D, num, ___, ___) \
+ V(BooleanNegateTOS, 0, ___, ___, ___) \
+ V(Throw, A, num, ___, ___) \
+ V(Entry, A_B_C, num, num, num) \
+ V(EntryOpt, A_B_C, num, num, num) \
+ V(Frame, D, num, ___, ___) \
+ V(SetFrame, A, num, ___, num) \
+ V(AllocateContext, D, num, ___, ___) \
+ V(CloneContext, 0, ___, ___, ___) \
+ V(MoveSpecial, A_D, reg, num, ___) \
+ V(InstantiateType, D, lit, ___, ___) \
+ V(InstantiateTypeArgumentsTOS, A_D, num, lit, ___) \
+ V(AssertAssignable, D, num, lit, ___) \
+ V(AssertBoolean, A, num, ___, ___) \
+ V(CheckStack, 0, ___, ___, ___) \
+ V(DebugStep, 0, ___, ___, ___) \
+ V(DebugBreak, A, num, ___, ___) \
+
+typedef uint32_t Instr;
+
+class Bytecode {
+ public:
+ enum Opcode {
+#define DECLARE_BYTECODE(name, encoding, op1, op2, op3) k##name,
+BYTECODES_LIST(DECLARE_BYTECODE)
+#undef DECLARE_BYTECODE
+ };
+
+ static const intptr_t kOpShift = 0;
+ static const intptr_t kAShift = 8;
+ static const intptr_t kAMask = 0xFF;
+ static const intptr_t kBShift = 16;
+ static const intptr_t kBMask = 0xFF;
+ static const intptr_t kCShift = 24;
+ static const intptr_t kCMask = 0xFF;
+ static const intptr_t kDShift = 16;
+ static const intptr_t kDMask = 0xFFFF;
+
+ static Instr Encode(Opcode op, uintptr_t a, uintptr_t b, uintptr_t c) {
+ ASSERT((a & kAMask) == a);
+ ASSERT((b & kBMask) == b);
+ ASSERT((c & kCMask) == c);
+ return op | (a << kAShift) | (b << kBShift) | (c << kCShift);
+ }
+
+ static Instr Encode(Opcode op, uintptr_t a, uintptr_t d) {
+ ASSERT((a & kAMask) == a);
+ ASSERT((d & kDMask) == d);
+ return op | (a << kAShift) | (d << kDShift);
+ }
+
+ static Instr EncodeSigned(Opcode op, uintptr_t a, intptr_t x) {
+ ASSERT((a & kAMask) == a);
+ ASSERT((x << kDShift) >> kDShift == x);
+ return op | (a << kAShift) | (x << kDShift);
+ }
+
+ static Instr EncodeSigned(Opcode op, intptr_t x) {
+ ASSERT((x << kAShift) >> kAShift == x);
+ return op | (x << kAShift);
+ }
+
+ static Instr Encode(Opcode op) {
+ return op;
+ }
+
+ DART_FORCE_INLINE static uint8_t DecodeA(Instr bc) {
+ return (bc >> kAShift) & kAMask;
+ }
+
+ DART_FORCE_INLINE static uint16_t DecodeD(Instr bc) {
+ return (bc >> kDShift) & kDMask;
+ }
+
+ DART_FORCE_INLINE static Opcode DecodeOpcode(Instr bc) {
+ return static_cast<Opcode>(bc & 0xFF);
+ }
+
+ DART_FORCE_INLINE static uint8_t DecodeArgc(Instr call) {
+#if defined(DEBUG)
+ const Opcode op = DecodeOpcode(call);
+ ASSERT((op == Bytecode::kStaticCall) ||
+ (op == Bytecode::kInstanceCall) ||
+ (op == Bytecode::kInstanceCall2) ||
+ (op == Bytecode::kInstanceCall3) ||
+ (op == Bytecode::kDebugBreak));
+#endif
+ return (call >> 8) & 0xFF;
+ }
+};
+
+// Various dummy declarations to make shared code compile.
+// TODO(vegorov) we need to prune away as much dead code as possible instead
+// of just making it compile.
+typedef int16_t Register;
+
+const int16_t FPREG = 0;
+const int16_t SPREG = 1;
+const intptr_t kNumberOfCpuRegisters = 20;
+const intptr_t kDartAvailableCpuRegs = 0;
+const intptr_t kNoRegister = -1;
+const intptr_t kReservedCpuRegisters = 0;
+const intptr_t ARGS_DESC_REG = 0;
+const intptr_t CODE_REG = 0;
+const intptr_t kExceptionObjectReg = 0;
+const intptr_t kStackTraceObjectReg = 0;
+const intptr_t CTX = 0;
+
+enum FpuRegister {
+ kNoFpuRegister = -1,
+ kFakeFpuRegister,
+ kNumberOfDummyFpuRegisters,
+};
+const FpuRegister FpuTMP = kFakeFpuRegister;
+const intptr_t kNumberOfFpuRegisters = 1;
+
+enum Condition { EQ, NE };
+
+} // namespace dart
+
+#endif // VM_CONSTANTS_DBC_H_
diff --git a/runtime/vm/cpu.h b/runtime/vm/cpu.h
index 2fffb25..3b93489 100644
--- a/runtime/vm/cpu.h
+++ b/runtime/vm/cpu.h
@@ -33,6 +33,8 @@
#include "vm/cpu_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/cpu_mips.h"
+#elif defined(TARGET_ARCH_DBC)
+#include "vm/cpu_dbc.h"
#else
#error Unknown architecture.
#endif
diff --git a/runtime/vm/cpu_dbc.cc b/runtime/vm/cpu_dbc.cc
new file mode 100644
index 0000000..8fcff5b
--- /dev/null
+++ b/runtime/vm/cpu_dbc.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h"
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/cpu.h"
+
+
+namespace dart {
+
+
+void CPU::FlushICache(uword start, uword size) {
+ // Nothing to do.
+}
+
+
+const char* CPU::Id() {
+ return "dbc";
+}
+
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/cpu_dbc.h b/runtime/vm/cpu_dbc.h
new file mode 100644
index 0000000..b437beb
--- /dev/null
+++ b/runtime/vm/cpu_dbc.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, 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_CPU_DBC_H_
+#define VM_CPU_DBC_H_
+
+#include "vm/allocation.h"
+#include "vm/simulator.h"
+
+namespace dart {
+
+class HostCPUFeatures: public AllStatic {
+ public:
+ static const char* hardware() { return "simdbc"; }
+};
+
+class TargetCPUFeatures : public AllStatic {
+ public:
+ static void InitOnce() {}
+ static void Cleanup() {}
+
+ static bool double_truncate_round_supported() {
+ return true;
+ }
+};
+
+} // namespace dart
+
+#endif // VM_CPU_DBC_H_
diff --git a/runtime/vm/cpu_test.cc b/runtime/vm/cpu_test.cc
index 6ccdebe..7ffbe6f 100644
--- a/runtime/vm/cpu_test.cc
+++ b/runtime/vm/cpu_test.cc
@@ -32,6 +32,8 @@
#else // defined(HOST_ARCH_MIPS)
EXPECT_STREQ("simmips", CPU::Id());
#endif // defined(HOST_ARCH_MIPS)
+#elif defined(TARGET_ARCH_DBC)
+ EXPECT_STREQ("dbc", CPU::Id());
#else
#error Architecture was not detected as supported by Dart.
#endif
diff --git a/runtime/vm/cpuinfo_test.cc b/runtime/vm/cpuinfo_test.cc
index 0b6113b..2b587f1 100644
--- a/runtime/vm/cpuinfo_test.cc
+++ b/runtime/vm/cpuinfo_test.cc
@@ -9,11 +9,13 @@
namespace dart {
+#if !defined(TARGET_ARCH_DBC)
UNIT_TEST_CASE(GetCpuModelTest) {
const char* cpumodel = CpuInfo::GetCpuModel();
EXPECT_NE(strlen(cpumodel), 0UL);
// caller is responsible for deleting the returned cpumodel string.
free(const_cast<char*>(cpumodel));
}
+#endif
} // namespace dart
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 0041d9a..d005cee 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -80,6 +80,40 @@
};
+static void CheckOffsets() {
+#define CHECK_OFFSET(expr, offset) \
+ if ((expr) != (offset)) { \
+ FATAL2("%s == %" Pd, #expr, (expr)); \
+ } \
+
+#if defined(TARGET_ARCH_ARM)
+ // These offsets are embedded in precompiled instructions. We need simarm
+ // (compiler) and arm (runtime) to agree.
+ CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
+ CHECK_OFFSET(Isolate::heap_offset(), 8);
+ CHECK_OFFSET(Thread::stack_limit_offset(), 4);
+ CHECK_OFFSET(Thread::object_null_offset(), 36);
+#endif
+#if defined(TARGET_ARCH_MIPS)
+ // These offsets are embedded in precompiled instructions. We need simmips
+ // (compiler) and mips (runtime) to agree.
+ CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
+ CHECK_OFFSET(Isolate::heap_offset(), 8);
+ CHECK_OFFSET(Thread::stack_limit_offset(), 4);
+ CHECK_OFFSET(Thread::object_null_offset(), 36);
+#endif
+#if defined(TARGET_ARCH_ARM64)
+ // These offsets are embedded in precompiled instructions. We need simarm64
+ // (compiler) and arm64 (runtime) to agree.
+ CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
+ CHECK_OFFSET(Isolate::heap_offset(), 16);
+ CHECK_OFFSET(Thread::stack_limit_offset(), 8);
+ CHECK_OFFSET(Thread::object_null_offset(), 72);
+#endif
+#undef CHECK_OFFSET
+}
+
+
const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
const uint8_t* instructions_snapshot,
const uint8_t* data_snapshot,
@@ -92,10 +126,20 @@
Dart_FileCloseCallback file_close,
Dart_EntropySource entropy_source,
Dart_GetVMServiceAssetsArchive get_service_assets) {
+ CheckOffsets();
// TODO(iposva): Fix race condition here.
if (vm_isolate_ != NULL || !Flags::Initialized()) {
return "VM already initialized or flags not initialized.";
}
+#if defined(DART_PRECOMPILED_RUNTIME)
+ if (instructions_snapshot == NULL) {
+ return "Precompiled runtime requires a precompiled snapshot";
+ }
+#else
+ if (instructions_snapshot != NULL) {
+ return "JIT runtime cannot run a precompiled snapshot";
+ }
+#endif
set_thread_exit_callback(thread_exit);
SetFileCallbacks(file_open, file_read, file_write, file_close);
set_entropy_source_callback(entropy_source);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index e8c31a9..c0a2fc5 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1495,8 +1495,8 @@
FullSnapshotWriter writer(vm_isolate_snapshot_buffer,
isolate_snapshot_buffer,
- NULL, /* instructions_snapshot_buffer */
ApiReallocate,
+ NULL, /* instructions_writer */
false, /* snapshot_code */
true /* vm_isolate_is_symbolic */);
writer.WriteFullSnapshot();
@@ -2152,7 +2152,6 @@
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
- API_TIMELINE_DURATION;
if (Api::IsSmi(integer)) {
*value = Api::SmiValue(integer);
return Api::Success();
@@ -2181,7 +2180,6 @@
DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer,
uint64_t* value) {
- API_TIMELINE_DURATION;
// Fast path for Smis.
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
@@ -2241,7 +2239,6 @@
DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
- API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(T, Double::New(value));
@@ -2250,7 +2247,6 @@
DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj,
double* value) {
- API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());
const Double& obj = Api::UnwrapDoubleHandle(Z, double_obj);
if (obj.IsNull()) {
@@ -4823,7 +4819,6 @@
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args,
int index) {
- API_TIMELINE_DURATION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
if ((index < 0) || (index >= arguments->NativeArgCount())) {
return Api::NewError(
@@ -4836,7 +4831,6 @@
DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args) {
- API_TIMELINE_DURATION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
return arguments->NativeArgCount();
}
@@ -4895,7 +4889,6 @@
DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args,
int index,
int64_t* value) {
- API_TIMELINE_DURATION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
if ((index < 0) || (index >= arguments->NativeArgCount())) {
return Api::NewError(
@@ -4913,7 +4906,6 @@
DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args,
int index,
bool* value) {
- API_TIMELINE_DURATION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
if ((index < 0) || (index >= arguments->NativeArgCount())) {
return Api::NewError(
@@ -4931,7 +4923,6 @@
DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args,
int index,
double* value) {
- API_TIMELINE_DURATION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
if ((index < 0) || (index >= arguments->NativeArgCount())) {
return Api::NewError(
@@ -5056,7 +5047,6 @@
// --- Scripts and Libraries ---
DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
bool retval) {
- API_TIMELINE_DURATION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
arguments->SetReturn(Bool::Get(retval));
}
@@ -5204,11 +5194,20 @@
CHECK_COMPILATION_ALLOWED(I);
ASSERT(snapshot->kind() == Snapshot::kScript);
+ NOT_IN_PRODUCT(TimelineDurationScope tds2(T,
+ Timeline::GetIsolateStream(), "ScriptSnapshotReader"));
+
ScriptSnapshotReader reader(snapshot->content(), snapshot->length(), T);
const Object& tmp = Object::Handle(Z, reader.ReadScriptSnapshot());
if (tmp.IsError()) {
return Api::NewHandle(T, tmp.raw());
}
+ NOT_IN_PRODUCT(if (tds2.enabled()) {
+ tds2.SetNumArguments(2);
+ tds2.FormatArgument(0, "snapshotSize", "%" Pd, snapshot->length());
+ tds2.FormatArgument(1, "heapSize", "%" Pd64,
+ I->heap()->UsedInWords(Heap::kOld) * kWordSize);
+ });
library ^= tmp.raw();
library.set_debuggable(true);
I->object_store()->set_root_library(library);
@@ -5976,6 +5975,7 @@
if (event == NULL) {
return;
}
+ label = strdup(label);
switch (type) {
case Dart_Timeline_Event_Begin:
event->Begin(label, timestamp0);
@@ -6004,6 +6004,7 @@
default:
FATAL("Unknown Dart_Timeline_Event_Type");
}
+ event->set_owns_label(true);
event->SetNumArguments(argument_count);
for (intptr_t i = 0; i < argument_count; i++) {
event->CopyArgument(i, argument_names[i], argument_values[i]);
@@ -6034,13 +6035,27 @@
}
-DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshotAssembly(
uint8_t** vm_isolate_snapshot_buffer,
intptr_t* vm_isolate_snapshot_size,
uint8_t** isolate_snapshot_buffer,
intptr_t* isolate_snapshot_size,
- uint8_t** instructions_snapshot_buffer,
- intptr_t* instructions_snapshot_size) {
+ uint8_t** assembly_buffer,
+ intptr_t* assembly_size) {
+ UNREACHABLE();
+ return 0;
+}
+
+
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshotBlob(
+ uint8_t** vm_isolate_snapshot_buffer,
+ intptr_t* vm_isolate_snapshot_size,
+ uint8_t** isolate_snapshot_buffer,
+ intptr_t* isolate_snapshot_size,
+ uint8_t** instructions_blob_buffer,
+ intptr_t* instructions_blob_size,
+ uint8_t** rodata_blob_buffer,
+ intptr_t* rodata_blob_size) {
UNREACHABLE();
return 0;
}
@@ -6069,13 +6084,13 @@
}
-DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshotAssembly(
uint8_t** vm_isolate_snapshot_buffer,
intptr_t* vm_isolate_snapshot_size,
uint8_t** isolate_snapshot_buffer,
intptr_t* isolate_snapshot_size,
- uint8_t** instructions_snapshot_buffer,
- intptr_t* instructions_snapshot_size) {
+ uint8_t** assembly_buffer,
+ intptr_t* assembly_size) {
ASSERT(FLAG_load_deferred_eagerly);
API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());
@@ -6096,26 +6111,84 @@
if (isolate_snapshot_size == NULL) {
RETURN_NULL_ERROR(isolate_snapshot_size);
}
- if (instructions_snapshot_buffer == NULL) {
- RETURN_NULL_ERROR(instructions_snapshot_buffer);
+ if (assembly_buffer == NULL) {
+ RETURN_NULL_ERROR(assembly_buffer);
}
- if (instructions_snapshot_size == NULL) {
- RETURN_NULL_ERROR(instructions_snapshot_size);
- }
- // Finalize all classes if needed.
- Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
- if (::Dart_IsError(state)) {
- return state;
+ if (assembly_size == NULL) {
+ RETURN_NULL_ERROR(assembly_size);
}
I->heap()->CollectAllGarbage();
+ AssemblyInstructionsWriter instructions_writer(assembly_buffer,
+ ApiReallocate,
+ 2 * MB /* initial_size */);
PrecompiledSnapshotWriter writer(vm_isolate_snapshot_buffer,
isolate_snapshot_buffer,
- instructions_snapshot_buffer,
- ApiReallocate);
+ ApiReallocate,
+ &instructions_writer);
writer.WriteFullSnapshot();
*vm_isolate_snapshot_size = writer.VmIsolateSnapshotSize();
*isolate_snapshot_size = writer.IsolateSnapshotSize();
- *instructions_snapshot_size = writer.InstructionsSnapshotSize();
+ *assembly_size = instructions_writer.AssemblySize();
+
+ return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshotBlob(
+ uint8_t** vm_isolate_snapshot_buffer,
+ intptr_t* vm_isolate_snapshot_size,
+ uint8_t** isolate_snapshot_buffer,
+ intptr_t* isolate_snapshot_size,
+ uint8_t** instructions_blob_buffer,
+ intptr_t* instructions_blob_size,
+ uint8_t** rodata_blob_buffer,
+ intptr_t* rodata_blob_size) {
+ ASSERT(FLAG_load_deferred_eagerly);
+ API_TIMELINE_DURATION;
+ DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
+ if (I->compilation_allowed()) {
+ return Dart_NewApiError("Isolate is not precompiled. "
+ "Did you forget to call Dart_Precompile?");
+ }
+ if (vm_isolate_snapshot_buffer == NULL) {
+ RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
+ }
+ if (vm_isolate_snapshot_size == NULL) {
+ RETURN_NULL_ERROR(vm_isolate_snapshot_size);
+ }
+ if (isolate_snapshot_buffer == NULL) {
+ RETURN_NULL_ERROR(isolate_snapshot_buffer);
+ }
+ if (isolate_snapshot_size == NULL) {
+ RETURN_NULL_ERROR(isolate_snapshot_size);
+ }
+ if (instructions_blob_buffer == NULL) {
+ RETURN_NULL_ERROR(instructions_blob_buffer);
+ }
+ if (instructions_blob_size == NULL) {
+ RETURN_NULL_ERROR(instructions_blob_size);
+ }
+ if (rodata_blob_buffer == NULL) {
+ RETURN_NULL_ERROR(instructions_blob_buffer);
+ }
+ if (rodata_blob_size == NULL) {
+ RETURN_NULL_ERROR(instructions_blob_size);
+ }
+ I->heap()->CollectAllGarbage();
+ BlobInstructionsWriter instructions_writer(instructions_blob_buffer,
+ rodata_blob_buffer,
+ ApiReallocate,
+ 2 * MB /* initial_size */);
+ PrecompiledSnapshotWriter writer(vm_isolate_snapshot_buffer,
+ isolate_snapshot_buffer,
+ ApiReallocate,
+ &instructions_writer);
+ writer.WriteFullSnapshot();
+ *vm_isolate_snapshot_size = writer.VmIsolateSnapshotSize();
+ *isolate_snapshot_size = writer.IsolateSnapshotSize();
+ *instructions_blob_size = instructions_writer.InstructionsBlobSize();
+ *rodata_blob_size = instructions_writer.RodataBlobSize();
return Api::Success();
}
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index ea55b49..c9e7769 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -103,15 +103,22 @@
}
}
// Now Call the invoke stub which will invoke the dart function.
+#if !defined(TARGET_ARCH_DBC)
invokestub entrypoint = reinterpret_cast<invokestub>(
StubCode::InvokeDartCode_entry()->EntryPoint());
+#endif
const Code& code = Code::Handle(zone, function.CurrentCode());
ASSERT(!code.IsNull());
ASSERT(thread->no_callback_scope_depth() == 0);
ScopedIsolateStackLimits stack_limit(thread);
SuspendLongJumpScope suspend_long_jump_scope(thread);
TransitionToGenerated transition(thread);
-#if defined(USING_SIMULATOR)
+#if defined(TARGET_ARCH_DBC)
+ return Simulator::Current()->Call(code,
+ arguments_descriptor,
+ arguments,
+ thread);
+#elif defined(USING_SIMULATOR)
return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
reinterpret_cast<intptr_t>(entrypoint),
reinterpret_cast<intptr_t>(&code),
@@ -322,23 +329,26 @@
// argument count; the positional argument count; a sequence of (name,
// position) pairs, sorted by name, for each named optional argument; and
// a terminating null to simplify iterating in generated code.
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
const intptr_t descriptor_len = LengthFor(num_named_args);
- Array& descriptor = Array::Handle(Array::New(descriptor_len, Heap::kOld));
+ Array& descriptor = Array::Handle(
+ zone, Array::New(descriptor_len, Heap::kOld));
// Set total number of passed arguments.
descriptor.SetAt(kCountIndex, Smi::Handle(Smi::New(num_arguments)));
// Set number of positional arguments.
descriptor.SetAt(kPositionalCountIndex, Smi::Handle(Smi::New(num_pos_args)));
// Set alphabetically sorted entries for named arguments.
- String& name = String::Handle();
- Smi& pos = Smi::Handle();
+ String& name = String::Handle(zone);
+ Smi& pos = Smi::Handle(zone);
+ String& previous_name = String::Handle(zone);
+ Smi& previous_pos = Smi::Handle(zone);
for (intptr_t i = 0; i < num_named_args; i++) {
name ^= optional_arguments_names.At(i);
pos = Smi::New(num_pos_args + i);
intptr_t insert_index = kFirstNamedEntryIndex + (kNamedEntrySize * i);
// Shift already inserted pairs with "larger" names.
- String& previous_name = String::Handle();
- Smi& previous_pos = Smi::Handle();
while (insert_index > kFirstNamedEntryIndex) {
intptr_t previous_index = insert_index - kNamedEntrySize;
previous_name ^= descriptor.At(previous_index + kNameOffset);
@@ -359,7 +369,7 @@
// Share the immutable descriptor when possible by canonicalizing it.
descriptor.MakeImmutable();
- descriptor ^= descriptor.CheckAndCanonicalize(NULL);
+ descriptor ^= descriptor.CheckAndCanonicalize(thread, NULL);
ASSERT(!descriptor.IsNull());
return descriptor.raw();
}
@@ -379,9 +389,12 @@
// Build the arguments descriptor array, which consists of the total
// argument count; the positional argument count; and
// a terminating null to simplify iterating in generated code.
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
const intptr_t descriptor_len = LengthFor(0);
- Array& descriptor = Array::Handle(Array::New(descriptor_len, Heap::kOld));
- const Smi& arg_count = Smi::Handle(Smi::New(num_arguments));
+ Array& descriptor = Array::Handle(
+ zone, Array::New(descriptor_len, Heap::kOld));
+ const Smi& arg_count = Smi::Handle(zone, Smi::New(num_arguments));
// Set total number of passed arguments.
descriptor.SetAt(kCountIndex, arg_count);
@@ -395,7 +408,7 @@
// Share the immutable descriptor when possible by canonicalizing it.
descriptor.MakeImmutable();
if (canonicalize) {
- descriptor ^= descriptor.CheckAndCanonicalize(NULL);
+ descriptor ^= descriptor.CheckAndCanonicalize(thread, NULL);
}
ASSERT(!descriptor.IsNull());
return descriptor.raw();
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 0f9597f..8c530ea 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -86,6 +86,19 @@
static RawArray* NewNonCached(intptr_t count, bool canonicalize = true);
+ // Used by Simulator to parse argument descriptors.
+ static intptr_t name_index(intptr_t index) {
+ return kFirstNamedEntryIndex +
+ (index * kNamedEntrySize) +
+ kNameOffset;
+ }
+
+ static intptr_t position_index(intptr_t index) {
+ return kFirstNamedEntryIndex +
+ (index * kNamedEntrySize) +
+ kPositionOffset;
+ }
+
const Array& array_;
// A cache of VM heap allocated arguments descriptors.
@@ -93,6 +106,7 @@
friend class SnapshotReader;
friend class SnapshotWriter;
+ friend class Simulator;
DISALLOW_COPY_AND_ASSIGN(ArgumentsDescriptor);
};
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index f47e822..58452a0 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -387,6 +387,16 @@
current_ += len;
}
+ void WriteWord(uword value) {
+ const intptr_t len = sizeof(uword);
+ if ((end_ - current_) < len) {
+ Resize(len);
+ }
+ ASSERT((end_ - current_) >= len);
+ *reinterpret_cast<uword*>(current_) = value;
+ current_ += len;
+ }
+
void Print(const char* format, ...) {
va_list args;
va_start(args, format);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index aa66533..6afad63 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -231,7 +231,9 @@
void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_));
+#if !defined(TARGET_ARCH_DBC)
visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_));
+#endif
}
@@ -859,24 +861,25 @@
}
+DART_FORCE_INLINE static RawObject* GetVariableValue(uword addr) {
+ return *reinterpret_cast<RawObject**>(addr);
+}
+
+
RawObject* ActivationFrame::GetParameter(intptr_t index) {
intptr_t num_parameters = function().num_fixed_parameters();
ASSERT(0 <= index && index < num_parameters);
- intptr_t reverse_index = num_parameters - index;
if (function().NumOptionalParameters() > 0) {
// If the function has optional parameters, the first positional parameter
// can be in a number of places in the caller's frame depending on how many
// were actually supplied at the call site, but they are copied to a fixed
// place in the callee's frame.
- uword var_address = fp() + ((kFirstLocalSlotFromFp - index) * kWordSize);
- return reinterpret_cast<RawObject*>(
- *reinterpret_cast<uword*>(var_address));
+ return GetVariableValue(LocalVarAddress(fp(),
+ (kFirstLocalSlotFromFp - index)));
} else {
- uword var_address = fp() + (kParamEndSlotFromFp * kWordSize)
- + (reverse_index * kWordSize);
- return reinterpret_cast<RawObject*>(
- *reinterpret_cast<uword*>(var_address));
+ intptr_t reverse_index = num_parameters - index;
+ return GetVariableValue(ParamAddress(fp(), reverse_index));
}
}
@@ -889,9 +892,7 @@
RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) {
if (deopt_frame_.IsNull()) {
- uword var_address = fp() + slot_index * kWordSize;
- return reinterpret_cast<RawObject*>(
- *reinterpret_cast<uword*>(var_address));
+ return GetVariableValue(LocalVarAddress(fp(), slot_index));
} else {
return deopt_frame_.At(deopt_frame_offset_ + slot_index);
}
@@ -1171,7 +1172,12 @@
bpt_location_(NULL),
next_(NULL),
breakpoint_kind_(kind),
- saved_value_(Code::null()) {
+#if !defined(TARGET_ARCH_DBC)
+ saved_value_(Code::null())
+#else
+ saved_value_(Bytecode::kTrap)
+#endif
+ {
ASSERT(!code.IsNull());
ASSERT(token_pos_.IsReal());
ASSERT(pc_ != 0);
@@ -2693,11 +2699,11 @@
if (stepping_fp_ != 0) {
// There is an "interesting frame" set. Only pause at appropriate
// locations in this frame.
- if (stepping_fp_ > frame->fp()) {
+ if (IsCalleeFrameOf(stepping_fp_, frame->fp())) {
// We are i n a callee of the frame we're interested in.
// Ignore this stepping break.
return Error::null();
- } else if (frame->fp() > stepping_fp_) {
+ } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) {
// We returned from the "interesting frame", there can be no more
// stepping breaks for it. Pause at the next appropriate location
// and let the user set the "interesting" frame again.
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index 4d00a34..ab83339 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -227,7 +227,14 @@
CodeBreakpoint* next_;
RawPcDescriptors::Kind breakpoint_kind_;
+#if !defined(TARGET_ARCH_DBC)
RawCode* saved_value_;
+#else
+ // When running on the DBC interpreter we patch bytecode in place with
+ // DebugBreak. This is an instruction that was replaced. DebugBreak
+ // will execute it after the breakpoint.
+ Instr saved_value_;
+#endif
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(CodeBreakpoint);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 0be2d29..80311f1 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -282,8 +282,13 @@
res = Dart_ActivationFrameGetFramePointer(frame, &frame_pointer);
EXPECT_TRUE(res);
if (i > 0) {
+#if !defined(TARGET_ARCH_DBC)
// We expect the stack to grow from high to low addresses.
EXPECT_GT(frame_pointer, last_frame_pointer);
+#else
+ // On DBC stack grows upwards from low to high addresses.
+ EXPECT_LT(frame_pointer, last_frame_pointer);
+#endif
}
last_frame_pointer = frame_pointer;
if (i < expected_frames) {
diff --git a/runtime/vm/debugger_dbc.cc b/runtime/vm/debugger_dbc.cc
new file mode 100644
index 0000000..5f82cd5
--- /dev/null
+++ b/runtime/vm/debugger_dbc.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h"
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/code_patcher.h"
+#include "vm/cpu.h"
+#include "vm/debugger.h"
+#include "vm/instructions.h"
+#include "vm/stub_code.h"
+
+namespace dart {
+
+#ifndef PRODUCT
+
+RawCode* CodeBreakpoint::OrigStubAddress() const {
+ return reinterpret_cast<RawCode*>(static_cast<uintptr_t>(saved_value_));
+}
+
+
+static Instr* CallInstructionFromReturnAddress(uword pc) {
+ return reinterpret_cast<Instr*>(pc) - 1;
+}
+
+
+void CodeBreakpoint::PatchCode() {
+ ASSERT(!is_enabled_);
+ const Code& code = Code::Handle(code_);
+ const Instructions& instrs = Instructions::Handle(code.instructions());
+ {
+ WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ saved_value_ = *CallInstructionFromReturnAddress(pc_);
+ switch (breakpoint_kind_) {
+ case RawPcDescriptors::kIcCall:
+ case RawPcDescriptors::kUnoptStaticCall: {
+ // DebugBreak has an A operand matching the call it replaces.
+ // This ensures that Return instructions continue to work - as they
+ // look at calls to figure out how many arguments to drop.
+ *CallInstructionFromReturnAddress(pc_) =
+ Bytecode::Encode(Bytecode::kDebugBreak,
+ Bytecode::DecodeArgc(saved_value_),
+ 0,
+ 0);
+ break;
+ }
+
+ case RawPcDescriptors::kRuntimeCall: {
+ *CallInstructionFromReturnAddress(pc_) = Bytecode::kDebugBreak;
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ }
+ }
+ is_enabled_ = true;
+}
+
+
+void CodeBreakpoint::RestoreCode() {
+ ASSERT(is_enabled_);
+ const Code& code = Code::Handle(code_);
+ const Instructions& instrs = Instructions::Handle(code.instructions());
+ {
+ WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
+ switch (breakpoint_kind_) {
+ case RawPcDescriptors::kIcCall:
+ case RawPcDescriptors::kUnoptStaticCall:
+ case RawPcDescriptors::kRuntimeCall: {
+ *CallInstructionFromReturnAddress(pc_) = saved_value_;
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ is_enabled_ = false;
+}
+
+#endif // !PRODUCT
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index ecef279..614b976 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -660,12 +660,16 @@
Function& function = Function::Handle(deopt_context->zone());
function ^= deopt_context->ObjectAt(object_table_index_);
if (function.IsNull()) {
+ // There are no deoptimization stubs on DBC.
+#if !defined(TARGET_ARCH_DBC)
*reinterpret_cast<RawObject**>(dest_addr) = deopt_context->is_lazy_deopt()
? StubCode::DeoptimizeLazy_entry()->code()
: StubCode::Deoptimize_entry()->code();
+#endif
return;
}
+#if !defined(TARGET_ARCH_DBC)
// We don't always have the Code object for the frame's corresponding
// unoptimized code as it may have been collected. Use a stub as the pc
// marker until we can recreate that Code object during deferred
@@ -673,6 +677,7 @@
// a pc marker.
*reinterpret_cast<RawObject**>(dest_addr) =
StubCode::FrameAwaitingMaterialization_entry()->code();
+#endif
deopt_context->DeferPcMarkerMaterialization(object_table_index_, dest_addr);
}
diff --git a/runtime/vm/disassembler_dbc.cc b/runtime/vm/disassembler_dbc.cc
new file mode 100644
index 0000000..85d734d
--- /dev/null
+++ b/runtime/vm/disassembler_dbc.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/disassembler.h"
+
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
+#if defined(TARGET_ARCH_DBC)
+
+#include "platform/assert.h"
+#include "vm/constants_dbc.h"
+#include "vm/cpu.h"
+
+namespace dart {
+
+static const char* kOpcodeNames[] = {
+#define BYTECODE_NAME(name, encoding, op1, op2, op3) #name,
+ BYTECODES_LIST(BYTECODE_NAME)
+#undef BYTECODE_NAME
+};
+
+static const size_t kOpcodeCount =
+ sizeof(kOpcodeNames) / sizeof(kOpcodeNames[0]);
+
+typedef void (*BytecodeFormatter)(char* buffer,
+ intptr_t size,
+ uword pc,
+ uint32_t bc);
+typedef void (*Fmt)(char** buf, intptr_t* size, uword pc, int32_t value);
+
+
+template <typename ValueType>
+void FormatOperand(char** buf,
+ intptr_t* size,
+ const char* fmt,
+ ValueType value) {
+ intptr_t written = OS::SNPrint(*buf, *size, fmt, value);
+ if (written < *size) {
+ *buf += written;
+ *size += written;
+ } else {
+ *size = -1;
+ }
+}
+
+
+static void Fmt___(char** buf, intptr_t* size, uword pc, int32_t value) {}
+
+
+static void Fmttgt(char** buf, intptr_t* size, uword pc, int32_t value) {
+ FormatOperand(buf, size, "-> %" Px, pc + (value << 2));
+}
+
+
+static void Fmtlit(char** buf, intptr_t* size, uword pc, int32_t value) {
+ FormatOperand(buf, size, "k%d", value);
+}
+
+
+static void Fmtreg(char** buf, intptr_t* size, uword pc, int32_t value) {
+ FormatOperand(buf, size, "r%d", value);
+}
+
+
+static void Fmtxeg(char** buf, intptr_t* size, uword pc, int32_t value) {
+ FormatOperand(buf, size, "R(%d)", value);
+}
+
+
+static void Fmtnum(char** buf, intptr_t* size, uword pc, int32_t value) {
+ FormatOperand(buf, size, "#%d", value);
+}
+
+
+static void Apply(char** buf,
+ intptr_t* size,
+ uword pc,
+ Fmt fmt,
+ int32_t value,
+ const char* suffix) {
+ if (*size <= 0) {
+ return;
+ }
+
+ fmt(buf, size, pc, value);
+ if (*size > 0) {
+ FormatOperand(buf, size, "%s", suffix);
+ }
+}
+
+
+static void Format0(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {}
+
+
+static void FormatT(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t x = static_cast<int32_t>(op) >> 8;
+ Apply(&buf, &size, pc, op1, x, "");
+}
+
+
+static void FormatA(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t a = (op & 0xFF00) >> 8;
+ Apply(&buf, &size, pc, op1, a, "");
+}
+
+
+static void FormatA_D(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t a = (op & 0xFF00) >> 8;
+ const int32_t bc = op >> 16;
+ Apply(&buf, &size, pc, op1, a, ", ");
+ Apply(&buf, &size, pc, op2, bc, "");
+}
+
+
+static void FormatA_X(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t a = (op & 0xFF00) >> 8;
+ const int32_t bc = static_cast<int32_t>(op) >> 16;
+ Apply(&buf, &size, pc, op1, a, ", ");
+ Apply(&buf, &size, pc, op2, bc, "");
+}
+
+
+static void FormatX(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t bc = static_cast<int32_t>(op) >> 16;
+ Apply(&buf, &size, pc, op1, bc, "");
+}
+
+
+static void FormatD(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t bc = op >> 16;
+ Apply(&buf, &size, pc, op1, bc, "");
+}
+
+
+static void FormatA_B_C(char* buf,
+ intptr_t size,
+ uword pc,
+ uint32_t op,
+ Fmt op1,
+ Fmt op2,
+ Fmt op3) {
+ const int32_t a = (op >> 8) & 0xFF;
+ const int32_t b = (op >> 16) & 0xFF;
+ const int32_t c = (op >> 24) & 0xFF;
+ Apply(&buf, &size, pc, op1, a, ", ");
+ Apply(&buf, &size, pc, op2, b, ", ");
+ Apply(&buf, &size, pc, op3, c, "");
+}
+
+
+#define BYTECODE_FORMATTER(name, encoding, op1, op2, op3) \
+ static void Format##name(char* buf, intptr_t size, uword pc, uint32_t op) { \
+ Format##encoding(buf, size, pc, op, Fmt##op1, Fmt##op2, Fmt##op3); \
+ }
+BYTECODES_LIST(BYTECODE_FORMATTER)
+#undef BYTECODE_FORMATTER
+
+
+static const BytecodeFormatter kFormatters[] = {
+#define BYTECODE_FORMATTER(name, encoding, op1, op2, op3) &Format##name,
+ BYTECODES_LIST(BYTECODE_FORMATTER)
+#undef BYTECODE_FORMATTER
+};
+
+
+void Disassembler::DecodeInstruction(char* hex_buffer,
+ intptr_t hex_size,
+ char* human_buffer,
+ intptr_t human_size,
+ int* out_instr_size,
+ uword pc) {
+ const uint32_t instr = *reinterpret_cast<uint32_t*>(pc);
+ const uint8_t opcode = instr & 0xFF;
+ ASSERT(opcode < kOpcodeCount);
+ size_t name_size =
+ OS::SNPrint(human_buffer, human_size, "%-10s\t", kOpcodeNames[opcode]);
+
+ human_buffer += name_size;
+ human_size -= name_size;
+ kFormatters[opcode](human_buffer, human_size, pc, instr);
+
+ OS::SNPrint(hex_buffer, hex_size, "%08x", instr);
+ if (out_instr_size) {
+ *out_instr_size = sizeof(uint32_t);
+ }
+}
+
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/disassembler_test.cc b/runtime/vm/disassembler_test.cc
index d07e174..8df643e 100644
--- a/runtime/vm/disassembler_test.cc
+++ b/runtime/vm/disassembler_test.cc
@@ -9,7 +9,9 @@
namespace dart {
-#ifndef PRODUCT
+// TODO(vegorov) this test is disabled on DBC because there is no PopRegister
+// method on DBC assembler.
+#if !defined(PRODUCT) && !defined(TARGET_ARCH_DBC)
TEST_CASE(Disassembler) {
Assembler assembler;
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 37d8184..60118f1 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -374,8 +374,8 @@
return xmm_regs[reg];
}
- void AppendToBuffer(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
- void AppendAddressToBuffer(uint8_t* addr);
+ void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+ void PrintAddress(uint8_t* addr);
int PrintOperands(const char* mnem,
OperandType op_order,
@@ -388,7 +388,9 @@
int PrintRightOperand(uint8_t* modrmp);
int PrintRightByteOperand(uint8_t* modrmp);
int PrintRightXMMOperand(uint8_t* modrmp);
+ void PrintDisp(int disp, const char* after);
int PrintImmediate(uint8_t* data, OperandSize size);
+ void PrintImmediateValue(int64_t value);
int PrintImmediateOp(uint8_t* data);
const char* TwoByteMnemonic(uint8_t opcode);
int TwoByteOpcodeInstruction(uint8_t* data);
@@ -406,7 +408,7 @@
bool DecodeInstructionType(uint8_t** data);
void UnimplementedInstruction() {
- AppendToBuffer("'Unimplemented Instruction'");
+ Print("'Unimplemented Instruction'");
}
char* buffer_; // Decode instructions into this buffer.
@@ -426,7 +428,7 @@
// Append the str to the output buffer.
-void DisassemblerX64::AppendToBuffer(const char* format, ...) {
+void DisassemblerX64::Print(const char* format, ...) {
intptr_t available = buffer_size_ - buffer_pos_;
if (available <= 1) {
ASSERT(buffer_[buffer_pos_] == '\0');
@@ -454,7 +456,8 @@
case 0:
if ((rm & 7) == 5) {
int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
- AppendToBuffer("[rip%s%#x]", disp < 0 ? "-" : "+", Utils::Abs(disp));
+ Print("[rip");
+ PrintDisp(disp, "]");
return 5;
} else if ((rm & 7) == 4) {
// Codes for SIB byte.
@@ -464,28 +467,27 @@
if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
// index == rsp means no index. Only use sib byte with no index for
// rsp and r12 base.
- AppendToBuffer("[%s]", NameOfCPURegister(base));
+ Print("[%s]", NameOfCPURegister(base));
return 2;
} else if (base == 5) {
// base == rbp means no base register (when mod == 0).
int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
- AppendToBuffer("[%s*%d+%#x]",
- NameOfCPURegister(index),
- 1 << scale, disp);
+ Print("[%s*%d", NameOfCPURegister(index), 1 << scale);
+ PrintDisp(disp, "]");
return 6;
} else if (index != 4 && base != 5) {
// [base+index*scale]
- AppendToBuffer("[%s+%s*%d]",
- NameOfCPURegister(base),
- NameOfCPURegister(index),
- 1 << scale);
+ Print("[%s+%s*%d]",
+ NameOfCPURegister(base),
+ NameOfCPURegister(index),
+ 1 << scale);
return 2;
} else {
UnimplementedInstruction();
return 1;
}
} else {
- AppendToBuffer("[%s]", NameOfCPURegister(rm));
+ Print("[%s]", NameOfCPURegister(rm));
return 1;
}
break;
@@ -498,41 +500,27 @@
int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
: *reinterpret_cast<char*>(modrmp + 2);
if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
- if (-disp > 0) {
- AppendToBuffer("[%s-%#x]", NameOfCPURegister(base), -disp);
- } else {
- AppendToBuffer("[%s+%#x]", NameOfCPURegister(base), disp);
- }
+ Print("[%s", NameOfCPURegister(base));
+ PrintDisp(disp, "]");
} else {
- if (-disp > 0) {
- AppendToBuffer("[%s+%s*%d-%#x]",
- NameOfCPURegister(base),
- NameOfCPURegister(index),
- 1 << scale,
- -disp);
- } else {
- AppendToBuffer("[%s+%s*%d+%#x]",
- NameOfCPURegister(base),
- NameOfCPURegister(index),
- 1 << scale,
- disp);
- }
+ Print("[%s+%s*%d",
+ NameOfCPURegister(base),
+ NameOfCPURegister(index),
+ 1 << scale);
+ PrintDisp(disp, "]");
}
return mod == 2 ? 6 : 3;
} else {
// No sib.
int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
: *reinterpret_cast<char*>(modrmp + 1);
- if (-disp > 0) {
- AppendToBuffer("[%s-%#x]", NameOfCPURegister(rm), -disp);
- } else {
- AppendToBuffer("[%s+%#x]", NameOfCPURegister(rm), disp);
- }
+ Print("[%s", NameOfCPURegister(rm));
+ PrintDisp(disp, "]");
return (mod == 2) ? 5 : 2;
}
break;
case 3:
- AppendToBuffer("%s", (this->*register_name)(rm));
+ Print("%s", (this->*register_name)(rm));
return 1;
default:
UnimplementedInstruction();
@@ -567,10 +555,29 @@
value = 0; // Initialize variables on all paths to satisfy the compiler.
count = 0;
}
- AppendToBuffer("%#" Px64 "", value);
+ PrintImmediateValue(value);
return count;
}
+void DisassemblerX64::PrintImmediateValue(int64_t value) {
+ if ((value >= 0) && (value <= 9)) {
+ Print("%" Pd64 "", value);
+ } else {
+ Print("%#" Px64 "", value);
+ }
+}
+
+void DisassemblerX64::PrintDisp(int disp, const char* after) {
+ if (-disp > 0) {
+ Print("-%#x", -disp);
+ } else {
+ Print("+%#x", disp);
+ }
+ if (after != NULL) Print("%s", after);
+}
+
+
+
// Returns number of bytes used by machine instruction, including *data byte.
// Writes immediate instructions to 'tmp_buffer_'.
@@ -608,9 +615,9 @@
default:
UnimplementedInstruction();
}
- AppendToBuffer("%s%c ", mnem, operand_size_code());
+ Print("%s%c ", mnem, operand_size_code());
int count = PrintRightOperand(data + 1);
- AppendToBuffer(",");
+ Print(",");
OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
count += PrintImmediate(data + 1 + count, immediate_size);
return 1 + count;
@@ -644,15 +651,15 @@
default:
UnimplementedInstruction();
}
- AppendToBuffer("%s%c %s",
- mnem,
- operand_size_code(),
- NameOfCPURegister(rm));
+ Print("%s%c %s",
+ mnem,
+ operand_size_code(),
+ NameOfCPURegister(rm));
return 2;
} else if (regop == 0) {
- AppendToBuffer("test%c ", operand_size_code());
+ Print("test%c ", operand_size_code());
int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
- AppendToBuffer(",0x");
+ Print(",");
count += PrintImmediate(data + 1 + count, operand_size());
return 1 + count;
} else {
@@ -712,15 +719,15 @@
imm8 = *(data + 2);
num_bytes = 3;
}
- AppendToBuffer("%s%c %s,",
- mnem,
- operand_size_code(),
- byte_size_operand_ ? NameOfByteCPURegister(rm)
- : NameOfCPURegister(rm));
+ Print("%s%c %s,",
+ mnem,
+ operand_size_code(),
+ byte_size_operand_ ? NameOfByteCPURegister(rm)
+ : NameOfCPURegister(rm));
if (op == 0xD2) {
- AppendToBuffer("cl");
+ Print("cl");
} else {
- AppendToBuffer("%d", imm8);
+ Print("%d", imm8);
}
return num_bytes;
}
@@ -758,19 +765,16 @@
: NameOfCPURegister(regop);
switch (op_order) {
case REG_OPER_OP_ORDER: {
- AppendToBuffer("%s%c %s,",
- mnem,
- operand_size_code(),
- register_name);
+ Print("%s%c %s,", mnem, operand_size_code(), register_name);
advance = byte_size_operand_ ? PrintRightByteOperand(data)
: PrintRightOperand(data);
break;
}
case OPER_REG_OP_ORDER: {
- AppendToBuffer("%s%c ", mnem, operand_size_code());
+ Print("%s%c ", mnem, operand_size_code());
advance = byte_size_operand_ ? PrintRightByteOperand(data)
: PrintRightOperand(data);
- AppendToBuffer(",%s", register_name);
+ Print(",%s", register_name);
break;
}
default:
@@ -803,9 +807,9 @@
}
-void DisassemblerX64::AppendAddressToBuffer(uint8_t* addr_byte_ptr) {
+void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) {
uword addr = reinterpret_cast<uword>(addr_byte_ptr);
- AppendToBuffer("%#" Px "", addr);
+ Print("%#" Px "", addr);
// Try to print as heap object or stub name
if (((addr & kSmiTagMask) == kHeapObjectTag) &&
reinterpret_cast<RawObject*>(addr)->IsWellFormed() &&
@@ -819,25 +823,25 @@
const Array& arr = Array::Cast(obj);
intptr_t len = arr.Length();
if (len > 5) len = 5; // Print a max of 5 elements.
- AppendToBuffer(" Array[");
+ Print(" Array[");
int i = 0;
Object& element = Object::Handle();
while (i < len) {
element = arr.At(i);
- if (i > 0) AppendToBuffer(", ");
- AppendToBuffer("%s", ObjectToCStringNoGC(element));
+ if (i > 0) Print(", ");
+ Print("%s", ObjectToCStringNoGC(element));
i++;
}
- if (i < arr.Length()) AppendToBuffer(", ...");
- AppendToBuffer("]");
+ if (i < arr.Length()) Print(", ...");
+ Print("]");
return;
}
- AppendToBuffer(" '%s'", ObjectToCStringNoGC(obj));
+ Print(" '%s'", ObjectToCStringNoGC(obj));
} else {
// 'addr' is not an object, but probably a code address.
const char* name_of_stub = StubCode::NameOfStub(addr);
if (name_of_stub != NULL) {
- AppendToBuffer(" [stub: %s]", name_of_stub);
+ Print(" [stub: %s]", name_of_stub);
}
}
}
@@ -848,8 +852,8 @@
ASSERT(0xEB == *data);
uint8_t b = *(data + 1);
uint8_t* dest = data + static_cast<int8_t>(b) + 2;
- AppendToBuffer("jmp ");
- AppendAddressToBuffer(dest);
+ Print("jmp ");
+ PrintAddress(dest);
return 2;
}
@@ -860,8 +864,8 @@
uint8_t cond = *(data + 1) & 0x0F;
uint8_t* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
const char* mnem = conditional_code_suffix[cond];
- AppendToBuffer("j%s ", mnem);
- AppendAddressToBuffer(dest);
+ Print("j%s ", mnem);
+ PrintAddress(dest);
return 6; // includes 0x0F
}
@@ -872,8 +876,8 @@
uint8_t b = *(data + 1);
uint8_t* dest = data + static_cast<int8_t>(b) + 2;
const char* mnem = conditional_code_suffix[cond];
- AppendToBuffer("j%s ", mnem);
- AppendAddressToBuffer(dest);
+ Print("j%s ", mnem);
+ PrintAddress(dest);
return 2;
}
@@ -883,7 +887,7 @@
ASSERT(0x0F == *data);
uint8_t cond = *(data + 1) & 0x0F;
const char* mnem = conditional_code_suffix[cond];
- AppendToBuffer("set%s%c ", mnem, operand_size_code());
+ Print("set%s%c ", mnem, operand_size_code());
PrintRightByteOperand(data + 2);
return 3; // includes 0x0F
}
@@ -942,7 +946,7 @@
default: UnimplementedInstruction();
}
- AppendToBuffer("%s ", mnem);
+ Print("%s ", mnem);
int count = PrintRightOperand(modrm_start);
return count + 1;
}
@@ -1058,9 +1062,9 @@
}
if (has_register) {
- AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
+ Print("%s st%d", mnem, modrm_byte & 0x7);
} else {
- AppendToBuffer("%s", mnem);
+ Print("%s", mnem);
}
return 2;
}
@@ -1078,11 +1082,11 @@
} else if ((current & 0xF0) == 0x40) { // REX prefix.
setRex(current);
// TODO(srdjan): Should we enable printing of REX.W?
- // if (rex_w()) AppendToBuffer("REX.W ");
+ // if (rex_w()) Print("REX.W ");
} else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
group_1_prefix_ = current;
} else if (current == 0xF0) {
- AppendToBuffer("lock ");
+ Print("lock ");
} else { // Not a prefix - an opcode.
break;
}
@@ -1098,13 +1102,13 @@
// String move or compare operations.
if (group_1_prefix_ == REP_PREFIX) {
// REP.
- AppendToBuffer("rep ");
+ Print("rep ");
}
// TODO(srdjan): Should we enable printing of REX.W?
- // if (rex_w()) AppendToBuffer("REX.W ");
- AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
+ // if (rex_w()) Print("REX.W ");
+ Print("%s%c", idesc.mnem, operand_size_code());
} else {
- AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
+ Print("%s%c", idesc.mnem, operand_size_code());
}
(*data)++;
break;
@@ -1119,16 +1123,16 @@
break;
case REGISTER_INSTR:
- AppendToBuffer("%s%c %s",
- idesc.mnem,
- operand_size_code(),
- NameOfCPURegister(base_reg(current & 0x07)));
+ Print("%s%c %s",
+ idesc.mnem,
+ operand_size_code(),
+ NameOfCPURegister(base_reg(current & 0x07)));
(*data)++;
break;
case PUSHPOP_INSTR:
- AppendToBuffer("%s %s",
- idesc.mnem,
- NameOfCPURegister(base_reg(current & 0x07)));
+ Print("%s %s",
+ idesc.mnem,
+ NameOfCPURegister(base_reg(current & 0x07)));
(*data)++;
break;
case MOVE_REG_INSTR: {
@@ -1152,17 +1156,17 @@
default:
UNREACHABLE();
}
- AppendToBuffer("mov%c %s,",
- operand_size_code(),
- NameOfCPURegister(base_reg(current & 0x07)));
- AppendAddressToBuffer(addr);
+ Print("mov%c %s,",
+ operand_size_code(),
+ NameOfCPURegister(base_reg(current & 0x07)));
+ PrintAddress(addr);
break;
}
case CALL_JUMP_INSTR: {
uint8_t* addr = *data + *reinterpret_cast<int32_t*>(*data + 1) + 5;
- AppendToBuffer("%s ", idesc.mnem);
- AppendAddressToBuffer(addr);
+ Print("%s ", idesc.mnem);
+ PrintAddress(addr);
(*data) += 5;
break;
}
@@ -1170,8 +1174,8 @@
case SHORT_IMMEDIATE_INSTR: {
uint8_t* addr =
reinterpret_cast<uint8_t*>(*reinterpret_cast<int32_t*>(*data + 1));
- AppendToBuffer("%s rax, ", idesc.mnem);
- AppendAddressToBuffer(addr);
+ Print("%s rax, ", idesc.mnem);
+ PrintAddress(addr);
(*data) += 5;
break;
}
@@ -1200,25 +1204,25 @@
if (opcode == 0xC6) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("shufpd %s, ", NameOfXMMRegister(regop));
+ Print("shufpd %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
- AppendToBuffer(" [%x]", *current);
+ Print(" [%x]", *current);
current++;
} else if (opcode == 0x3A) {
uint8_t third_byte = *current;
current = data + 3;
if (third_byte == 0x17) {
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("extractps "); // reg/m32, xmm, imm8
+ Print("extractps "); // reg/m32, xmm, imm8
current += PrintRightOperand(current);
- AppendToBuffer(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
+ Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
current += 1;
} else if (third_byte == 0x0b) {
get_modrm(*current, &mod, ®op, &rm);
// roundsd xmm, xmm/m64, imm8
- AppendToBuffer("roundsd %s, ", NameOfCPURegister(regop));
+ Print("roundsd %s, ", NameOfCPURegister(regop));
current += PrintRightOperand(current);
- AppendToBuffer(", %d", (*current) & 3);
+ Print(", %d", (*current) & 3);
current += 1;
} else {
UnimplementedInstruction();
@@ -1235,38 +1239,38 @@
} else if (mod == 2) { // 32-bit displacement.
current += 4;
} // else no immediate displacement.
- AppendToBuffer("nop");
+ Print("nop");
} else if (opcode == 0x28) {
- AppendToBuffer("movapd %s, ", NameOfXMMRegister(regop));
+ Print("movapd %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x29) {
- AppendToBuffer("movapd ");
+ Print("movapd ");
current += PrintRightXMMOperand(current);
- AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x6E) {
- AppendToBuffer("mov%c %s,",
- rex_w() ? 'q' : 'd',
- NameOfXMMRegister(regop));
+ Print("mov%c %s,",
+ rex_w() ? 'q' : 'd',
+ NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x6F) {
- AppendToBuffer("movdqa %s,",
- NameOfXMMRegister(regop));
+ Print("movdqa %s,",
+ NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x7E) {
- AppendToBuffer("mov%c ",
- rex_w() ? 'q' : 'd');
+ Print("mov%c ",
+ rex_w() ? 'q' : 'd');
current += PrintRightOperand(current);
- AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x7F) {
- AppendToBuffer("movdqa ");
+ Print("movdqa ");
current += PrintRightXMMOperand(current);
- AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0xD6) {
- AppendToBuffer("movq ");
+ Print("movq ");
current += PrintRightXMMOperand(current);
- AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x50) {
- AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
+ Print("movmskpd %s,", NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else {
const char* mnemonic = "?";
@@ -1307,7 +1311,7 @@
} else {
UnimplementedInstruction();
}
- AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
+ Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
}
}
@@ -1316,42 +1320,42 @@
if (opcode == 0x11 || opcode == 0x10) {
// MOVSD: Move scalar double-precision fp to/from/between XMM registers.
- AppendToBuffer("movsd ");
+ Print("movsd ");
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0x11) {
current += PrintRightXMMOperand(current);
- AppendToBuffer(",%s", NameOfXMMRegister(regop));
+ Print(",%s", NameOfXMMRegister(regop));
} else {
- AppendToBuffer("%s,", NameOfXMMRegister(regop));
+ Print("%s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
}
} else if (opcode == 0x2A) {
// CVTSI2SD: integer to XMM double conversion.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
+ Print("%sd %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x2C) {
// CVTTSD2SI:
// Convert with truncation scalar double-precision FP to integer.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("cvttsd2si%c %s,",
+ Print("cvttsd2si%c %s,",
operand_size_code(), NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x2D) {
// CVTSD2SI: Convert scalar double-precision FP to integer.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("cvtsd2si%c %s,",
+ Print("cvtsd2si%c %s,",
operand_size_code(), NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
// XMM arithmetic. Mnemonic was retrieved at the start of this function.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
+ Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else {
UnimplementedInstruction();
@@ -1360,46 +1364,46 @@
// Instructions with prefix 0xF3.
if (opcode == 0x11 || opcode == 0x10) {
// MOVSS: Move scalar double-precision fp to/from/between XMM registers.
- AppendToBuffer("movss ");
+ Print("movss ");
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0x11) {
current += PrintRightOperand(current);
- AppendToBuffer(",%s", NameOfXMMRegister(regop));
+ Print(",%s", NameOfXMMRegister(regop));
} else {
- AppendToBuffer("%s,", NameOfXMMRegister(regop));
+ Print("%s,", NameOfXMMRegister(regop));
current += PrintRightOperand(current);
}
} else if (opcode == 0x2A) {
// CVTSI2SS: integer to XMM single conversion.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
+ Print("%ss %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x2C) {
// CVTTSS2SI:
// Convert with truncation scalar single-precision FP to dword integer.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("cvttss2si%c %s,",
- operand_size_code(), NameOfCPURegister(regop));
+ Print("cvttss2si%c %s,",
+ operand_size_code(), NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x5A) {
// CVTSS2SD:
// Convert scalar single-precision FP to scalar double-precision FP.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
+ Print("cvtss2sd %s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x7E) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("movq %s, ", NameOfXMMRegister(regop));
+ Print("movq %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x58) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
+ Print("addss %s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else {
UnimplementedInstruction();
@@ -1417,42 +1421,42 @@
} else if (mod == 2) { // 32-bit displacement.
current += 4;
} // else no immediate displacement.
- AppendToBuffer("nop");
+ Print("nop");
} else if (opcode == 0x28) {
// movaps xmm, xmm/m128
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("movaps %s, ", NameOfXMMRegister(regop));
+ Print("movaps %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x29) {
// movaps xmm/m128, xmm
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("movaps ");
+ Print("movaps ");
current += PrintRightXMMOperand(current);
- AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x11) {
// movups xmm/m128, xmm
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("movups ");
+ Print("movups ");
current += PrintRightXMMOperand(current);
- AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x10) {
// movups xmm, xmm/m128
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("movups %s, ", NameOfXMMRegister(regop));
+ Print("movups %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x50) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
+ Print("movmskps %s,", NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xA2 || opcode == 0x31) {
// RDTSC or CPUID
- AppendToBuffer("%s", mnemonic);
+ Print("%s", mnemonic);
} else if ((opcode & 0xF0) == 0x40) {
// CMOVcc: conditional move.
@@ -1490,19 +1494,19 @@
}
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("%s %s, ", mnemonic, NameOfXMMRegister(regop));
+ Print("%s %s, ", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xC2 || opcode == 0xC6) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0xC2) {
- AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
+ Print("cmpps %s, ", NameOfXMMRegister(regop));
} else {
ASSERT(opcode == 0xC6);
- AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
+ Print("shufps %s, ", NameOfXMMRegister(regop));
}
current += PrintRightXMMOperand(current);
- AppendToBuffer(" [%x]", *current);
+ Print(" [%x]", *current);
current++;
} else if ((opcode & 0xF0) == 0x80) {
// Jcc: Conditional jump (branch).
@@ -1521,17 +1525,17 @@
} else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) ||
(opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
// SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test).
- AppendToBuffer("%s%c ", mnemonic, operand_size_code());
+ Print("%s%c ", mnemonic, operand_size_code());
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
current += PrintRightOperand(current);
- AppendToBuffer(",%s", NameOfCPURegister(regop));
+ Print(",%s", NameOfCPURegister(regop));
if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
// Done.
} else if ((opcode == 0xA5) || (opcode == 0xAD)) {
- AppendToBuffer(",cl");
+ Print(",cl");
} else {
- AppendToBuffer(",");
+ Print(",");
current += PrintImmediate(current, BYTE_SIZE);
}
} else {
@@ -1607,14 +1611,15 @@
if (!processed) {
switch (*data) {
case 0xC2:
- AppendToBuffer("ret %#x", *reinterpret_cast<uint16_t*>(data + 1));
+ Print("ret ");
+ PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1));
data += 3;
break;
case 0xC8:
- AppendToBuffer("enter %d, %d",
- *reinterpret_cast<uint16_t*>(data + 1),
- data[3]);
+ Print("enter %d, %d",
+ *reinterpret_cast<uint16_t*>(data + 1),
+ data[3]);
data += 4;
break;
@@ -1624,10 +1629,11 @@
get_modrm(*(data + 1), &mod, ®op, &rm);
int32_t imm = *data == 0x6B ? *(data + 2)
: *reinterpret_cast<int32_t*>(data + 2);
- AppendToBuffer("imul%c %s,%s,%#x",
- operand_size_code(),
- NameOfCPURegister(regop),
- NameOfCPURegister(rm), imm);
+ Print("imul%c %s,%s,",
+ operand_size_code(),
+ NameOfCPURegister(regop),
+ NameOfCPURegister(rm));
+ PrintImmediateValue(imm);
data += 2 + (*data == 0x6B ? 1 : 4);
break;
}
@@ -1646,7 +1652,7 @@
int mod, regop, rm;
get_modrm(*data, &mod, ®op, &rm);
if (regop == 0) {
- AppendToBuffer("pop ");
+ Print("pop ");
data += PrintRightOperand(data);
}
}
@@ -1677,9 +1683,9 @@
mnem = "???";
}
if (regop <= 1) {
- AppendToBuffer("%s%c ", mnem, operand_size_code());
+ Print("%s%c ", mnem, operand_size_code());
} else {
- AppendToBuffer("%s ", mnem);
+ Print("%s ", mnem);
}
data += PrintRightOperand(data);
}
@@ -1691,16 +1697,18 @@
bool is_byte = *data == 0xC6;
data++;
if (is_byte) {
- AppendToBuffer("movb ");
+ Print("movb ");
data += PrintRightByteOperand(data);
int32_t imm = *data;
- AppendToBuffer(",%#x", imm);
+ Print(",");
+ PrintImmediateValue(imm);
data++;
} else {
- AppendToBuffer("mov%c ", operand_size_code());
+ Print("mov%c ", operand_size_code());
data += PrintRightOperand(data);
int32_t imm = *reinterpret_cast<int32_t*>(data);
- AppendToBuffer(",%#x", imm);
+ Print(",");
+ PrintImmediateValue(imm);
data += 4;
}
}
@@ -1708,10 +1716,11 @@
case 0x80: {
data++;
- AppendToBuffer("cmpb ");
+ Print("cmpb ");
data += PrintRightByteOperand(data);
int32_t imm = *data;
- AppendToBuffer(",%#x", imm);
+ Print(",");
+ PrintImmediateValue(imm);
data++;
}
break;
@@ -1724,13 +1733,13 @@
data++;
get_modrm(*data, &mod, ®op, &rm);
if (is_byte) {
- AppendToBuffer("movb ");
+ Print("movb ");
data += PrintRightByteOperand(data);
- AppendToBuffer(",%s", NameOfByteCPURegister(regop));
+ Print(",%s", NameOfByteCPURegister(regop));
} else {
- AppendToBuffer("mov%c ", operand_size_code());
+ Print("mov%c ", operand_size_code());
data += PrintRightOperand(data);
- AppendToBuffer(",%s", NameOfCPURegister(regop));
+ Print(",%s", NameOfCPURegister(regop));
}
}
break;
@@ -1745,11 +1754,9 @@
case 0x97: {
int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
if (reg == 0) {
- AppendToBuffer("nop"); // Common name for xchg rax,rax.
+ Print("nop"); // Common name for xchg rax,rax.
} else {
- AppendToBuffer("xchg%c rax, %s",
- operand_size_code(),
- NameOfCPURegister(reg));
+ Print("xchg%c rax, %s", operand_size_code(), NameOfCPURegister(reg));
}
data++;
}
@@ -1776,13 +1783,10 @@
uint8_t is_32bit = (opcode >= 0xB8);
int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
if (is_32bit) {
- AppendToBuffer("mov%c %s, ",
- operand_size_code(),
- NameOfCPURegister(reg));
+ Print("mov%c %s,", operand_size_code(), NameOfCPURegister(reg));
data += PrintImmediate(data, DOUBLEWORD_SIZE);
} else {
- AppendToBuffer("movb %s, ",
- NameOfByteCPURegister(reg));
+ Print("movb %s,", NameOfByteCPURegister(reg));
data += PrintImmediate(data, BYTE_SIZE);
}
break;
@@ -1792,7 +1796,7 @@
int mod, regop, rm;
get_modrm(*data, &mod, ®op, &rm);
if (regop == 1) {
- AppendToBuffer("decb ");
+ Print("decb ");
data += PrintRightByteOperand(data);
} else {
UnimplementedInstruction();
@@ -1800,12 +1804,14 @@
break;
}
case 0x68:
- AppendToBuffer("push %#x", *reinterpret_cast<int32_t*>(data + 1));
+ Print("push ");
+ PrintImmediateValue(*reinterpret_cast<int32_t*>(data + 1));
data += 5;
break;
case 0x6A:
- AppendToBuffer("push %#x", *reinterpret_cast<int8_t*>(data + 1));
+ Print("push ");
+ PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1));
data += 2;
break;
@@ -1813,21 +1819,21 @@
case 0xA3:
switch (operand_size()) {
case DOUBLEWORD_SIZE: {
- AppendAddressToBuffer(
+ PrintAddress(
reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
if (*data == 0xA1) { // Opcode 0xA1
- AppendToBuffer("movzxlq rax,(");
- AppendAddressToBuffer(
+ Print("movzxlq rax,(");
+ PrintAddress(
reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
- AppendToBuffer(")");
+ Print(")");
} else { // Opcode 0xA3
- AppendToBuffer("movzxlq (");
- AppendAddressToBuffer(
+ Print("movzxlq (");
+ PrintAddress(
reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
- AppendToBuffer("),rax");
+ Print("),rax");
}
data += 5;
break;
@@ -1835,13 +1841,13 @@
case QUADWORD_SIZE: {
// New x64 instruction mov rax,(imm_64).
if (*data == 0xA1) { // Opcode 0xA1
- AppendToBuffer("movq rax,(");
- AppendAddressToBuffer(*reinterpret_cast<uint8_t**>(data + 1));
- AppendToBuffer(")");
+ Print("movq rax,(");
+ PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
+ Print(")");
} else { // Opcode 0xA3
- AppendToBuffer("movq (");
- AppendAddressToBuffer(*reinterpret_cast<uint8_t**>(data + 1));
- AppendToBuffer("),rax");
+ Print("movq (");
+ PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
+ Print("),rax");
}
data += 9;
break;
@@ -1853,7 +1859,8 @@
break;
case 0xA8:
- AppendToBuffer("test al,%#x", *reinterpret_cast<uint8_t*>(data + 1));
+ Print("test al,");
+ PrintImmediateValue(*reinterpret_cast<uint8_t*>(data + 1));
data += 2;
break;
@@ -1875,9 +1882,8 @@
default:
UNREACHABLE();
}
- AppendToBuffer("test%c rax,%#" Px64 "",
- operand_size_code(),
- value);
+ Print("test%c rax,", operand_size_code());
+ PrintImmediateValue(value);
break;
}
case 0xD1: // fall through
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index bac5c1e..b7e437b 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -16,10 +16,14 @@
VM_TEST_CASE(FindCodeObject) {
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
const int kLoopCount = 50000;
+ const int kScriptSize = 512 * KB;
+#elif defined(TARGET_ARCH_DBC)
+ const int kLoopCount = 60000;
+ const int kScriptSize = 1 * MB;
#else
const int kLoopCount = 25000;
-#endif
const int kScriptSize = 512 * KB;
+#endif
const int kNumFunctions = 1024;
char scriptChars[kScriptSize];
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index bbc7f05..58a5c6a 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -5,6 +5,12 @@
#ifndef VM_FLAG_LIST_H_
#define VM_FLAG_LIST_H_
+#if defined(TARGET_ARCH_DBC)
+#define USING_DBC 1
+#else
+#define USING_DBC 0
+#endif
+
// List of all flags in the VM.
// Flags can be one of three categories:
// * P roduct flags: Can be set in any of the deployment modes, including in
@@ -21,12 +27,12 @@
// R(name, product_value, type, default_value, comment)
// C(name, precompiled_value, product_value, type, default_value, comment)
#define FLAG_LIST(P, R, D, C) \
-P(allow_absolute_addresses, bool, true, \
- "Allow embedding absolute addresses in generated code.") \
P(always_megamorphic_calls, bool, false, \
"Instance call always as megamorphic.") \
-C(background_compilation, false, false, bool, false, \
+C(background_compilation, false, true, bool, true, \
"Run optimizing compilation in background") \
+R(background_compilation_stop_alot, false, bool, false, \
+ "Stress test system: stop background compiler often.") \
R(break_at_isolate_spawn, false, bool, false, \
"Insert a one-time breakpoint at the entrypoint for all spawned isolates") \
C(collect_code, false, true, bool, true, \
@@ -70,9 +76,9 @@
"Ratio of getter/setter usage used for double field unboxing heuristics") \
P(guess_icdata_cid, bool, true, \
"Artificially create type feedback for arithmetic etc. operations") \
-P(ic_range_profiling, bool, true, \
+P(ic_range_profiling, bool, !USING_DBC, \
"Generate special IC stubs collecting range information ") \
-P(interpret_irregexp, bool, false, \
+P(interpret_irregexp, bool, USING_DBC, \
"Use irregexp bytecode interpreter") \
P(lazy_dispatchers, bool, true, \
"Generate dispatchers lazily") \
@@ -119,7 +125,7 @@
"Print live ranges after allocation.") \
C(print_stop_message, false, false, bool, false, \
"Print stop message.") \
-R(profiler, false, bool, true, \
+R(profiler, false, bool, !USING_DBC, \
"Enable the profiler.") \
P(reorder_basic_blocks, bool, true, \
"Reorder basic blocks") \
@@ -159,7 +165,7 @@
"Optimize left shift to truncate if possible") \
P(use_cha_deopt, bool, true, \
"Use class hierarchy analysis even if it can cause deoptimization.") \
-P(use_field_guards, bool, true, \
+P(use_field_guards, bool, !USING_DBC, \
"Use field guards and track field types") \
C(use_osr, false, true, bool, true, \
"Use OSR") \
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 1f428174..69f7f16 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1460,54 +1460,6 @@
}
-static const String& BinaryOpAndMaskName(BinaryOpNode* node) {
- if (node->kind() == Token::kSHL) {
- return Library::PrivateCoreLibName(Symbols::_leftShiftWithMask32());
- }
- UNIMPLEMENTED();
- return String::ZoneHandle(Thread::Current()->zone(), String::null());
-}
-
-
-// <Expression> :: BinaryOp { kind: Token::Kind
-// left: <Expression>
-// right: <Expression>
-// mask32: constant }
-void EffectGraphVisitor::VisitBinaryOpWithMask32Node(
- BinaryOpWithMask32Node* node) {
- ASSERT((node->kind() != Token::kAND) && (node->kind() != Token::kOR));
- ValueGraphVisitor for_left_value(owner());
- node->left()->Visit(&for_left_value);
- Append(for_left_value);
- PushArgumentInstr* push_left = PushArgument(for_left_value.value());
-
- ValueGraphVisitor for_right_value(owner());
- node->right()->Visit(&for_right_value);
- Append(for_right_value);
- PushArgumentInstr* push_right = PushArgument(for_right_value.value());
-
- Value* mask_value = Bind(new(Z) ConstantInstr(
- Integer::ZoneHandle(Z, Integer::New(node->mask32(), Heap::kOld))));
- PushArgumentInstr* push_mask = PushArgument(mask_value);
-
- ZoneGrowableArray<PushArgumentInstr*>* arguments =
- new(Z) ZoneGrowableArray<PushArgumentInstr*>(3);
- arguments->Add(push_left);
- arguments->Add(push_right);
- // Call to special method 'BinaryOpAndMaskName(node)'.
- arguments->Add(push_mask);
- const intptr_t kNumArgsChecked = 2;
- InstanceCallInstr* call = new(Z) InstanceCallInstr(node->token_pos(),
- BinaryOpAndMaskName(node),
- Token::kILLEGAL,
- arguments,
- Object::null_array(),
- kNumArgsChecked,
- owner()->ic_data_array());
- ReturnDefinition(call);
-}
-
-
void EffectGraphVisitor::BuildTypecheckPushArguments(
TokenPosition token_pos,
PushArgumentInstr** push_instantiator_type_arguments_result) {
@@ -3499,6 +3451,8 @@
load->set_is_immutable(kind != MethodRecognizer::kGrowableArrayLength);
return ReturnDefinition(load);
}
+#if !defined(TARGET_ARCH_DBC)
+ // TODO(vegorov) add bytecode to support this method.
case MethodRecognizer::kClassIDgetID: {
LocalVariable* value_var =
node->scope()->LookupVariable(Symbols::Value(), true);
@@ -3506,6 +3460,7 @@
LoadClassIdInstr* load = new(Z) LoadClassIdInstr(value);
return ReturnDefinition(load);
}
+#endif
case MethodRecognizer::kGrowableArrayCapacity: {
Value* receiver = Bind(BuildLoadThisVar(node->scope(), token_pos));
LoadFieldInstr* data_load = new(Z) LoadFieldInstr(
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index cfdf133..6632df8 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -79,7 +79,6 @@
FLAG_inlining_constant_arguments_max_size_threshold = 100;
FLAG_inlining_constant_arguments_min_size_threshold = 30;
- FLAG_allow_absolute_addresses = false;
FLAG_always_megamorphic_calls = true;
FLAG_collect_dynamic_function_names = true;
FLAG_fields_may_be_reset = true;
@@ -503,7 +502,7 @@
continue;
}
-#if defined(DEBUG)
+#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
if (!is_optimizing()) {
FrameStateClear();
}
@@ -557,14 +556,14 @@
EndCodeSourceRange(instr->token_pos());
}
-#if defined(DEBUG)
+#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
if (!is_optimizing()) {
FrameStateUpdateWith(instr);
}
#endif
}
-#if defined(DEBUG)
+#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
ASSERT(is_optimizing() || FrameStateIsSafeToCall());
#endif
}
@@ -1147,14 +1146,18 @@
}
+// DBC is very different from other architectures in how it performs instance
+// and static calls because it does not use stubs.
+#if !defined(TARGET_ARCH_DBC)
void FlowGraphCompiler::GenerateInstanceCall(
intptr_t deopt_id,
TokenPosition token_pos,
intptr_t argument_count,
LocationSummary* locs,
const ICData& ic_data_in) {
- const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original());
+ ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original());
if (FLAG_precompiled_mode) {
+ ic_data = ic_data.AsUnaryClassChecks();
EmitSwitchableInstanceCall(ic_data, argument_count,
deopt_id, token_pos, locs);
return;
@@ -1285,7 +1288,7 @@
CheckClassIds(kClassIdReg, args, is_instance_lbl, &unknown);
assembler()->Bind(&unknown);
}
-
+#endif // !defined(TARGET_ARCH_DBC)
void FlowGraphCompiler::EmitComment(Instruction* instr) {
if (!FLAG_support_il_printer || !FLAG_support_disassembler) {
@@ -1300,6 +1303,8 @@
}
+#if !defined(TARGET_ARCH_DBC)
+// TODO(vegorov) enable edge-counters on DBC if we consider them beneficial.
bool FlowGraphCompiler::NeedsEdgeCounter(TargetEntryInstr* block) {
// Only emit an edge counter if there is not goto at the end of the block,
// except for the entry block.
@@ -1320,18 +1325,17 @@
UNREACHABLE();
return kNoRegister;
}
-
-
-static uword RegMaskBit(Register reg) {
- return ((reg) != kNoRegister) ? (1 << (reg)) : 0;
-}
+#endif
void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) {
ASSERT(!is_optimizing());
-
instr->InitializeLocationSummary(zone(),
false); // Not optimizing.
+
+ // No need to allocate registers based on LocationSummary on DBC as in
+ // unoptimized mode it's a stack based bytecode just like IR itself.
+#if !defined(TARGET_ARCH_DBC)
LocationSummary* locs = instr->locs();
bool blocked_registers[kNumberOfCpuRegisters];
@@ -1421,6 +1425,12 @@
}
locs->set_out(0, result_location);
}
+#endif // !defined(TARGET_ARCH_DBC)
+}
+
+
+static uword RegMaskBit(Register reg) {
+ return ((reg) != kNoRegister) ? (1 << (reg)) : 0;
}
@@ -1837,6 +1847,9 @@
}
+#if !defined(TARGET_ARCH_DBC)
+// DBC emits calls very differently from other architectures due to its
+// interpreted nature.
void FlowGraphCompiler::EmitPolymorphicInstanceCall(
const ICData& ic_data,
intptr_t argument_count,
@@ -1880,9 +1893,12 @@
}
}
}
+#endif
-
-#if defined(DEBUG)
+#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
+// TODO(vegorov) re-enable frame state tracking on DBC. It is
+// currently disabled because it relies on LocationSummaries and
+// we don't use them during unoptimized compilation on DBC.
void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) {
ASSERT(!is_optimizing());
@@ -1953,7 +1969,7 @@
ASSERT(!is_optimizing());
frame_state_.TruncateTo(0);
}
-#endif
+#endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC)
} // namespace dart
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 7c1fa0e..586dbdb 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -367,6 +367,15 @@
// Returns 'true' if regular code generation should be skipped.
bool TryIntrinsify();
+ void GenerateAssertAssignable(TokenPosition token_pos,
+ intptr_t deopt_id,
+ const AbstractType& dst_type,
+ const String& dst_name,
+ LocationSummary* locs);
+
+ // DBC emits calls very differently from all other architectures due to its
+ // interpreted nature.
+#if !defined(TARGET_ARCH_DBC)
void GenerateRuntimeCall(TokenPosition token_pos,
intptr_t deopt_id,
const RuntimeEntry& entry,
@@ -390,12 +399,6 @@
LocationSummary* locs,
const Function& target);
- void GenerateAssertAssignable(TokenPosition token_pos,
- intptr_t deopt_id,
- const AbstractType& dst_type,
- const String& dst_name,
- LocationSummary* locs);
-
void GenerateInstanceOf(TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& type,
@@ -426,12 +429,6 @@
void GenerateListTypeCheck(Register kClassIdReg,
Label* is_instance_lbl);
- void EmitComment(Instruction* instr);
-
- bool NeedsEdgeCounter(TargetEntryInstr* block);
-
- void EmitEdgeCounter(intptr_t edge_id);
-
void EmitOptimizedInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
@@ -489,8 +486,15 @@
bool needs_number_check,
TokenPosition token_pos);
+ bool NeedsEdgeCounter(TargetEntryInstr* block);
+
+ void EmitEdgeCounter(intptr_t edge_id);
+#endif // !defined(TARGET_ARCH_DBC)
+
void EmitTrySync(Instruction* instr, intptr_t try_index);
+ void EmitComment(Instruction* instr);
+
intptr_t StackSize() const;
// Returns assembler label associated with the given block entry.
@@ -637,6 +641,9 @@
LocationSummary* locs,
const ICData& ic_data);
+ // DBC handles type tests differently from all other architectures due
+ // to its interpreted nature.
+#if !defined(TARGET_ARCH_DBC)
// Type checking helper methods.
void CheckClassIds(Register class_id_reg,
const GrowableArray<intptr_t>& class_ids,
@@ -690,6 +697,7 @@
void GenerateBoolToJump(Register bool_reg, Label* is_true, Label* is_false);
void CopyParameters();
+#endif // !defined(TARGET_ARCH_DBC)
void GenerateInlinedGetter(intptr_t offset);
void GenerateInlinedSetter(intptr_t offset);
@@ -722,7 +730,10 @@
return stackmap_table_builder_;
}
-#if defined(DEBUG)
+ // TODO(vegorov) re-enable frame state tracking on DBC. It is
+ // currently disabled because it relies on LocationSummaries and
+ // we don't use them during unoptimized compilation on DBC.
+#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
void FrameStateUpdateWith(Instruction* instr);
void FrameStatePush(Definition* defn);
void FrameStatePop(intptr_t count);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index ace14d0..9c58044 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1319,7 +1319,30 @@
MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
+ // Load receiver into R0.
__ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
+ Label done;
+ if (name.raw() == Symbols::hashCode().raw()) {
+ Label megamorphic_call;
+ __ Comment("Inlined get:hashCode for Smi and OneByteString");
+ __ tst(R0, Operand(kSmiTagMask));
+ __ b(&done, EQ); // Is Smi (result is receiver).
+
+ // Use R9 (cache for megamorphic call) as scratch.
+ __ CompareClassId(R0, kOneByteStringCid, R9);
+ __ b(&megamorphic_call, NE);
+
+ __ mov(R9, Operand(R0)); // Preserve receiver in R9.
+ __ ldr(R0, FieldAddress(R0, String::hash_offset()));
+ ASSERT(Smi::New(0) == 0);
+ __ cmp(R0, Operand(0));
+
+ __ b(&done, NE); // Return if already computed.
+ __ mov(R0, Operand(R9)); // Restore receiver in R0.
+
+ __ Bind(&megamorphic_call);
+ __ Comment("Slow case: megamorphic call");
+ }
__ LoadObject(R9, cache);
if (FLAG_use_megamorphic_stub) {
__ BranchLink(*StubCode::MegamorphicLookup_entry());
@@ -1328,6 +1351,7 @@
}
__ blx(R1);
+ __ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
if (FLAG_precompiled_mode) {
@@ -1365,21 +1389,9 @@
LocationSummary* locs) {
__ Comment("SwitchableCall");
__ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
- if (ic_data.NumArgsTested() == 1) {
- __ LoadUniqueObject(R9, ic_data);
- __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
- } else {
- const String& name = String::Handle(zone(), ic_data.target_name());
- const Array& arguments_descriptor =
- Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
- ASSERT(!arguments_descriptor.IsNull() &&
- (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
- MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
-
- __ LoadUniqueObject(R9, cache);
- __ BranchLinkPatchable(*StubCode::MegamorphicLookup_entry());
- }
+ ASSERT(ic_data.NumArgsTested() == 1);
+ __ LoadUniqueObject(R9, ic_data);
+ __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
__ blx(R1);
AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos);
@@ -1516,7 +1528,7 @@
if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
DRegister d1 = EvenDRegisterOf(fpu_reg);
DRegister d2 = OddDRegisterOf(fpu_reg);
- // TOOD(regis): merge stores using vstmd instruction.
+ // TODO(regis): merge stores using vstmd instruction.
__ vstrd(d1, Address(SP, offset));
__ vstrd(d2, Address(SP, offset + 2 * kWordSize));
offset += kFpuRegisterSize;
@@ -1562,7 +1574,7 @@
if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
DRegister d1 = EvenDRegisterOf(fpu_reg);
DRegister d2 = OddDRegisterOf(fpu_reg);
- // TOOD(regis): merge loads using vldmd instruction.
+ // TODO(regis): merge loads using vldmd instruction.
__ vldrd(d1, Address(SP, offset));
__ vldrd(d2, Address(SP, offset + 2 * kWordSize));
offset += kFpuRegisterSize;
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index f872532..d62a23a 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1300,7 +1300,29 @@
MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
+ // Load receiver into R0.
__ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
+ Label done;
+ if (name.raw() == Symbols::hashCode().raw()) {
+ Label megamorphic_call;
+ __ Comment("Inlined get:hashCode for Smi and OneByteString");
+ __ tsti(R0, Immediate(kSmiTagMask));
+ __ b(&done, EQ); // Is Smi (result is receiver).
+
+ __ CompareClassId(R0, kOneByteStringCid);
+ __ b(&megamorphic_call, NE);
+
+ // Use R5 (cache for megamorphic call) as scratch.
+ __ mov(R5, R0); // Preserve receiver in R5, result in R0.
+ __ ldr(R0, FieldAddress(R0, String::hash_offset()));
+ __ CompareRegisters(R0, ZR);
+ __ b(&done, NE);
+ __ mov(R0, R5); // Restore receiver in R0,
+
+ __ Bind(&megamorphic_call);
+ __ Comment("Slow case: megamorphic call");
+ }
+
__ LoadObject(R5, cache);
if (FLAG_use_megamorphic_stub) {
__ BranchLink(*StubCode::MegamorphicLookup_entry());
@@ -1309,6 +1331,7 @@
}
__ blr(R1);
+ __ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
if (FLAG_precompiled_mode) {
@@ -1345,21 +1368,9 @@
LocationSummary* locs) {
__ Comment("SwitchableCall");
__ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
- if (ic_data.NumArgsTested() == 1) {
- __ LoadUniqueObject(R5, ic_data);
- __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
- } else {
- const String& name = String::Handle(zone(), ic_data.target_name());
- const Array& arguments_descriptor =
- Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
- ASSERT(!arguments_descriptor.IsNull() &&
- (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
- MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
-
- __ LoadUniqueObject(R5, cache);
- __ BranchLinkPatchable(*StubCode::MegamorphicLookup_entry());
- }
+ ASSERT(ic_data.NumArgsTested() == 1);
+ __ LoadUniqueObject(R5, ic_data);
+ __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
__ blr(R1);
AddCurrentDescriptor(RawPcDescriptors::kOther,
diff --git a/runtime/vm/flow_graph_compiler_dbc.cc b/runtime/vm/flow_graph_compiler_dbc.cc
new file mode 100644
index 0000000..2f3ff8e
--- /dev/null
+++ b/runtime/vm/flow_graph_compiler_dbc.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/flow_graph_compiler.h"
+
+#include "vm/ast_printer.h"
+#include "vm/compiler.h"
+#include "vm/cpu.h"
+#include "vm/dart_entry.h"
+#include "vm/deopt_instructions.h"
+#include "vm/il_printer.h"
+#include "vm/instructions.h"
+#include "vm/locations.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+#include "vm/stack_frame.h"
+#include "vm/stub_code.h"
+#include "vm/symbols.h"
+#include "vm/verified_memory.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
+DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
+DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic.");
+DECLARE_FLAG(bool, enable_simd_inline);
+DECLARE_FLAG(bool, use_megamorphic_stub);
+DECLARE_FLAG(charp, optimization_filter);
+
+void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+FlowGraphCompiler::~FlowGraphCompiler() {
+ // BlockInfos are zone-allocated, so their destructors are not called.
+ // Verify the labels explicitly here.
+ for (int i = 0; i < block_info_.length(); ++i) {
+ ASSERT(!block_info_[i]->jump_label()->IsLinked());
+ }
+}
+
+
+bool FlowGraphCompiler::SupportsUnboxedDoubles() {
+ return false;
+}
+
+
+bool FlowGraphCompiler::SupportsUnboxedMints() {
+ return false;
+}
+
+
+bool FlowGraphCompiler::SupportsUnboxedSimd128() {
+ return false;
+}
+
+
+bool FlowGraphCompiler::SupportsSinCos() {
+ return false;
+}
+
+
+bool FlowGraphCompiler::SupportsHardwareDivision() {
+ return true;
+}
+
+
+bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
+ return false;
+}
+
+
+void FlowGraphCompiler::EnterIntrinsicMode() {
+ ASSERT(!intrinsic_mode());
+ intrinsic_mode_ = true;
+}
+
+
+void FlowGraphCompiler::ExitIntrinsicMode() {
+ ASSERT(intrinsic_mode());
+ intrinsic_mode_ = false;
+}
+
+
+RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
+ DeoptInfoBuilder* builder,
+ const Array& deopt_table) {
+ UNIMPLEMENTED();
+ return TypedData::null();
+}
+
+
+void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler,
+ intptr_t stub_ix) {
+ UNIMPLEMENTED();
+}
+
+
+#define __ assembler()->
+
+
+void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
+ intptr_t deopt_id,
+ const AbstractType& dst_type,
+ const String& dst_name,
+ LocationSummary* locs) {
+ ASSERT(!is_optimizing());
+ SubtypeTestCache& test_cache = SubtypeTestCache::Handle();
+ if (!dst_type.IsVoidType() && dst_type.IsInstantiated()) {
+ test_cache = SubtypeTestCache::New();
+ }
+
+ __ PushConstant(dst_type);
+ __ PushConstant(dst_name);
+ __ AssertAssignable(__ AddConstant(test_cache));
+ AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos);
+}
+
+
+void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
+ if (!is_optimizing()) {
+ Definition* defn = instr->AsDefinition();
+ if ((defn != NULL) &&
+ (defn->tag() != Instruction::kPushArgument) &&
+ (defn->tag() != Instruction::kStoreIndexed) &&
+ (defn->tag() != Instruction::kStoreStaticField) &&
+ (defn->tag() != Instruction::kStoreLocal) &&
+ (defn->tag() != Instruction::kStoreInstanceField) &&
+ (defn->tag() != Instruction::kDropTemps) &&
+ (defn->tag() != Instruction::kPushTemp) &&
+ !defn->HasTemp()) {
+ __ Drop1();
+ }
+ }
+}
+
+
+void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
+ __ Move(0, -(1 + kParamEndSlotFromFp));
+ __ LoadField(0, 0, offset / kWordSize);
+ __ Return(0);
+}
+
+
+void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
+ __ Move(0, -(2 + kParamEndSlotFromFp));
+ __ Move(1, -(1 + kParamEndSlotFromFp));
+ __ StoreField(0, offset / kWordSize, 1);
+ __ LoadConstant(0, Object::Handle());
+ __ Return(0);
+}
+
+
+void FlowGraphCompiler::EmitFrameEntry() {
+ const Function& function = parsed_function().function();
+ const intptr_t num_fixed_params = function.num_fixed_parameters();
+ const int num_opt_pos_params = function.NumOptionalPositionalParameters();
+ const int num_opt_named_params = function.NumOptionalNamedParameters();
+ const int num_params =
+ num_fixed_params + num_opt_pos_params + num_opt_named_params;
+ const bool has_optional_params = (num_opt_pos_params != 0) ||
+ (num_opt_named_params != 0);
+ const int num_locals = parsed_function().num_stack_locals();
+ const intptr_t context_index =
+ -parsed_function().current_context_var()->index() - 1;
+
+ if (has_optional_params) {
+ __ EntryOpt(num_fixed_params, num_opt_pos_params, num_opt_named_params);
+ } else {
+ __ Entry(num_fixed_params, num_locals, context_index);
+ }
+
+ if (num_opt_named_params != 0) {
+ LocalScope* scope = parsed_function().node_sequence()->scope();
+
+ // Start by alphabetically sorting the names of the optional parameters.
+ LocalVariable** opt_param =
+ zone()->Alloc<LocalVariable*>(num_opt_named_params);
+ int* opt_param_position = zone()->Alloc<int>(num_opt_named_params);
+ for (int pos = num_fixed_params; pos < num_params; pos++) {
+ LocalVariable* parameter = scope->VariableAt(pos);
+ const String& opt_param_name = parameter->name();
+ int i = pos - num_fixed_params;
+ while (--i >= 0) {
+ LocalVariable* param_i = opt_param[i];
+ const intptr_t result = opt_param_name.CompareTo(param_i->name());
+ ASSERT(result != 0);
+ if (result > 0) break;
+ opt_param[i + 1] = opt_param[i];
+ opt_param_position[i + 1] = opt_param_position[i];
+ }
+ opt_param[i + 1] = parameter;
+ opt_param_position[i + 1] = pos;
+ }
+
+ for (intptr_t i = 0; i < num_opt_named_params; i++) {
+ const int param_pos = opt_param_position[i];
+ const Instance& value = parsed_function().DefaultParameterValueAt(
+ param_pos - num_fixed_params);
+ __ LoadConstant(param_pos, opt_param[i]->name());
+ __ LoadConstant(param_pos, value);
+ }
+ } else if (num_opt_pos_params != 0) {
+ for (intptr_t i = 0; i < num_opt_pos_params; i++) {
+ const Object& value = parsed_function().DefaultParameterValueAt(i);
+ __ LoadConstant(num_fixed_params + i, value);
+ }
+ }
+
+
+ ASSERT(num_locals > 0); // There is always at least context_var.
+ if (has_optional_params) {
+ ASSERT(!is_optimizing());
+ __ Frame(num_locals); // Reserve space for locals.
+ }
+
+ if (function.IsClosureFunction()) {
+ Register reg = context_index;
+ Register closure_reg = reg;
+ LocalScope* scope = parsed_function().node_sequence()->scope();
+ LocalVariable* local = scope->VariableAt(0);
+ if (local->index() > 0) {
+ __ Move(reg, -local->index());
+ } else {
+ closure_reg = -local->index() - 1;
+ }
+ __ LoadField(reg, closure_reg, Closure::context_offset() / kWordSize);
+ } else if (has_optional_params) {
+ __ LoadConstant(context_index,
+ Object::Handle(isolate()->object_store()->empty_context()));
+ }
+}
+
+
+void FlowGraphCompiler::CompileGraph() {
+ InitCompiler();
+
+ if (TryIntrinsify()) {
+ // Skip regular code generation.
+ return;
+ }
+
+ EmitFrameEntry();
+ VisitBlocks();
+}
+
+
+#undef __
+#define __ compiler_->assembler()->
+
+
+void ParallelMoveResolver::EmitMove(int index) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::EmitSwap(int index) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst,
+ const Address& src) {
+ UNREACHABLE();
+}
+
+
+void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
+ UNREACHABLE();
+}
+
+
+// Do not call or implement this function. Instead, use the form below that
+// uses an offset from the frame pointer instead of an Address.
+void ParallelMoveResolver::Exchange(Register reg, const Address& mem) {
+ UNREACHABLE();
+}
+
+
+// Do not call or implement this function. Instead, use the form below that
+// uses offsets from the frame pointer instead of Addresses.
+void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
+ UNREACHABLE();
+}
+
+
+void ParallelMoveResolver::Exchange(Register reg,
+ Register base_reg,
+ intptr_t stack_offset) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::Exchange(Register base_reg1,
+ intptr_t stack_offset1,
+ Register base_reg2,
+ intptr_t stack_offset2) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::SpillScratch(Register reg) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::RestoreScratch(Register reg) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
+ UNIMPLEMENTED();
+}
+
+
+void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
+ UNIMPLEMENTED();
+}
+
+
+#undef __
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index eac4f3c..8a7c349 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1300,7 +1300,27 @@
MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
+ // Load receiver into EBX.
__ movl(EBX, Address(ESP, (argument_count - 1) * kWordSize));
+ Label done;
+ if (name.raw() == Symbols::hashCode().raw()) {
+ Label try_onebytestring, megamorphic_call;
+ __ Comment("Inlined get:hashCode for Smi and OneByteString");
+ __ testl(EBX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &try_onebytestring, Assembler::kNearJump); // Non-smi value.
+ __ movl(EAX, EBX);
+ __ jmp(&done, Assembler::kNearJump);
+
+ __ Bind(&try_onebytestring);
+ __ CompareClassId(EBX, kOneByteStringCid, EAX);
+ __ j(NOT_EQUAL, &megamorphic_call, Assembler::kNearJump);
+ __ movl(EAX, FieldAddress(EBX, String::hash_offset()));
+ __ cmpl(EAX, Immediate(0));
+ __ j(NOT_EQUAL, &done, Assembler::kNearJump);
+
+ __ Bind(&megamorphic_call);
+ __ Comment("Slow case: megamorphic call");
+ }
__ LoadObject(ECX, cache);
if (FLAG_use_megamorphic_stub) {
__ Call(*StubCode::MegamorphicLookup_entry());
@@ -1309,6 +1329,7 @@
}
__ call(EBX);
+ __ Bind(&done);
AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId, token_pos);
RecordSafepoint(locs, slow_path_argument_count);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 3ec2756..9fa5d9f 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1327,7 +1327,28 @@
MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
+ // Load receiver into T0,
__ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
+ Label done;
+ if (name.raw() == Symbols::hashCode().raw()) {
+ Label try_onebytestring, megamorphic_call;
+ __ Comment("Inlined get:hashCode for Smi and OneByteString");
+ __ andi(CMPRES1, T0, Immediate(kSmiTagMask));
+ __ bne(CMPRES1, ZR, &try_onebytestring); // Not Smi.
+ __ mov(V0, T0);
+ __ b(&done);
+
+ __ Bind(&try_onebytestring);
+ __ LoadClassId(CMPRES1, T0); // Class ID check.
+ __ BranchNotEqual(
+ CMPRES1, Immediate(kOneByteStringCid), &megamorphic_call);
+
+ __ lw(V0, FieldAddress(T0, String::hash_offset()));
+ __ bne(V0, ZR, &done);
+
+ __ Bind(&megamorphic_call);
+ __ Comment("Slow case: megamorphic call");
+ }
__ LoadObject(S5, cache);
if (FLAG_use_megamorphic_stub) {
__ BranchLink(*StubCode::MegamorphicLookup_entry());
@@ -1336,6 +1357,7 @@
}
__ jalr(T1);
+ __ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
if (FLAG_precompiled_mode) {
@@ -1372,21 +1394,9 @@
LocationSummary* locs) {
__ Comment("SwitchableCall");
__ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
- if (ic_data.NumArgsTested() == 1) {
- __ LoadUniqueObject(S5, ic_data);
- __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
- } else {
- const String& name = String::Handle(zone(), ic_data.target_name());
- const Array& arguments_descriptor =
- Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
- ASSERT(!arguments_descriptor.IsNull() &&
- (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
- MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
-
- __ LoadUniqueObject(S5, cache);
- __ BranchLinkPatchable(*StubCode::MegamorphicLookup_entry());
- }
+ ASSERT(ic_data.NumArgsTested() == 1);
+ __ LoadUniqueObject(S5, ic_data);
+ __ BranchLinkPatchable(*StubCode::ICLookupThroughFunction_entry());
__ jalr(T1);
AddCurrentDescriptor(RawPcDescriptors::kOther,
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index e044923..def75aa 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1328,9 +1328,28 @@
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
-
__ Comment("MegamorphicCall");
+ // Load receiver into RDI.
__ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize));
+ Label done;
+ if (name.raw() == Symbols::hashCode().raw()) {
+ Label try_onebytestring, megamorphic_call;
+ __ Comment("Inlined get:hashCode for Smi and OneByteString");
+ __ testq(RDI, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &try_onebytestring, Assembler::kNearJump); // Non-smi value.
+ __ movq(RAX, RDI);
+ __ jmp(&done, Assembler::kNearJump);
+
+ __ Bind(&try_onebytestring);
+ __ CompareClassId(RDI, kOneByteStringCid);
+ __ j(NOT_EQUAL, &megamorphic_call, Assembler::kNearJump);
+ __ movq(RAX, FieldAddress(RDI, String::hash_offset()));
+ __ cmpq(RAX, Immediate(0));
+ __ j(NOT_EQUAL, &done, Assembler::kNearJump);
+
+ __ Bind(&megamorphic_call);
+ __ Comment("Slow case: megamorphic call");
+ }
__ LoadObject(RBX, cache);
if (FLAG_use_megamorphic_stub) {
__ Call(*StubCode::MegamorphicLookup_entry());
@@ -1339,6 +1358,7 @@
}
__ call(RCX);
+ __ Bind(&done);
RecordSafepoint(locs, slow_path_argument_count);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
if (FLAG_precompiled_mode) {
@@ -1375,21 +1395,9 @@
LocationSummary* locs) {
__ Comment("SwitchableCall");
__ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize));
- if (ic_data.NumArgsTested() == 1) {
- __ LoadUniqueObject(RBX, ic_data);
- __ CallPatchable(*StubCode::ICLookupThroughFunction_entry());
- } else {
- const String& name = String::Handle(zone(), ic_data.target_name());
- const Array& arguments_descriptor =
- Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
- ASSERT(!arguments_descriptor.IsNull() &&
- (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
- MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
-
- __ LoadUniqueObject(RBX, cache);
- __ CallPatchable(*StubCode::MegamorphicLookup_entry());
- }
+ ASSERT(ic_data.NumArgsTested() == 1);
+ __ LoadUniqueObject(RBX, ic_data);
+ __ CallPatchable(*StubCode::ICLookupThroughFunction_entry());
__ call(RCX);
AddCurrentDescriptor(RawPcDescriptors::kOther,
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index b1d188a..8accbf4 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -466,6 +466,11 @@
}
+CompileType CompileType::Smi() {
+ return Create(kSmiCid, Type::ZoneHandle(Type::SmiType()));
+}
+
+
CompileType CompileType::String() {
return FromAbstractType(Type::ZoneHandle(Type::StringType()), kNonNullable);
}
diff --git a/runtime/vm/hash_table.h b/runtime/vm/hash_table.h
index f4eb375..15317a1 100644
--- a/runtime/vm/hash_table.h
+++ b/runtime/vm/hash_table.h
@@ -137,6 +137,14 @@
smi_handle_ = Smi::New(0);
data_->SetAt(kOccupiedEntriesIndex, smi_handle_);
data_->SetAt(kDeletedEntriesIndex, smi_handle_);
+
+NOT_IN_PRODUCT(
+ data_->SetAt(kNumGrowsIndex, smi_handle_);
+ data_->SetAt(kNumLT5LookupsIndex, smi_handle_);
+ data_->SetAt(kNumLT25LookupsIndex, smi_handle_);
+ data_->SetAt(kNumGT25LookupsIndex, smi_handle_);
+) // !PRODUCT
+
for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) {
data_->SetAt(i, Object::sentinel());
}
@@ -154,17 +162,21 @@
const intptr_t num_entries = NumEntries();
ASSERT(NumOccupied() < num_entries);
// TODO(koda): Add salt.
+ NOT_IN_PRODUCT(intptr_t collisions = 0;)
uword hash = KeyTraits::Hash(key);
intptr_t probe = hash % num_entries;
// TODO(koda): Consider quadratic probing.
while (true) {
if (IsUnused(probe)) {
+ NOT_IN_PRODUCT(UpdateCollisions(collisions);)
return -1;
} else if (!IsDeleted(probe)) {
key_handle_ = GetKey(probe);
if (KeyTraits::IsMatch(key, key_handle_)) {
+ NOT_IN_PRODUCT(UpdateCollisions(collisions);)
return probe;
}
+ NOT_IN_PRODUCT(collisions += 1;)
}
// Advance probe.
probe++;
@@ -183,6 +195,7 @@
const intptr_t num_entries = NumEntries();
ASSERT(entry != NULL);
ASSERT(NumOccupied() < num_entries);
+ NOT_IN_PRODUCT(intptr_t collisions = 0;)
uword hash = KeyTraits::Hash(key);
intptr_t probe = hash % num_entries;
intptr_t deleted = -1;
@@ -190,6 +203,7 @@
while (true) {
if (IsUnused(probe)) {
*entry = (deleted != -1) ? deleted : probe;
+ NOT_IN_PRODUCT(UpdateCollisions(collisions);)
return false;
} else if (IsDeleted(probe)) {
if (deleted == -1) {
@@ -199,8 +213,10 @@
key_handle_ = GetKey(probe);
if (KeyTraits::IsMatch(key, key_handle_)) {
*entry = probe;
+ NOT_IN_PRODUCT(UpdateCollisions(collisions);)
return true;
}
+ NOT_IN_PRODUCT(collisions += 1;)
}
// Advance probe.
probe++;
@@ -279,10 +295,63 @@
return smi_handle_;
}
+NOT_IN_PRODUCT(
+ intptr_t NumGrows() const {
+ return GetSmiValueAt(kNumGrowsIndex);
+ }
+ intptr_t NumLT5Collisions() const {
+ return GetSmiValueAt(kNumLT5LookupsIndex);
+ }
+ intptr_t NumLT25Collisions() const {
+ return GetSmiValueAt(kNumLT25LookupsIndex);
+ }
+ intptr_t NumGT25Collisions() const {
+ return GetSmiValueAt(kNumGT25LookupsIndex);
+ }
+ void UpdateGrowth() const {
+ AdjustSmiValueAt(kNumGrowsIndex, 1);
+ }
+ void UpdateCollisions(intptr_t collisions) const {
+ if (data_->raw()->IsVMHeapObject()) {
+ return;
+ }
+ if (collisions < 5) {
+ AdjustSmiValueAt(kNumLT5LookupsIndex, 1);
+ } else if (collisions < 25) {
+ AdjustSmiValueAt(kNumLT25LookupsIndex, 1);
+ } else {
+ AdjustSmiValueAt(kNumGT25LookupsIndex, 1);
+ }
+ }
+ void PrintStats() const {
+ if (!KeyTraits::ReportStats()) {
+ return;
+ }
+ OS::Print("Stats for %s table :\n"
+ " Size of table = %" Pd ",Number of Occupied entries = %" Pd "\n"
+ " Number of Grows = %" Pd "\n"
+ " Number of look ups with < 5 collisions = %" Pd "\n"
+ " Number of look ups with < 25 collisions = %" Pd "\n"
+ " Number of look ups with > 25 collisions = %" Pd "\n",
+ KeyTraits::Name(),
+ NumEntries(), NumOccupied(),
+ NumGrows(),
+ NumLT5Collisions(), NumLT25Collisions(), NumGT25Collisions());
+ }
+) // !PRODUCT
+
protected:
static const intptr_t kOccupiedEntriesIndex = 0;
static const intptr_t kDeletedEntriesIndex = 1;
+#if defined(PRODUCT)
static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1;
+#else
+ static const intptr_t kNumGrowsIndex = 2;
+ static const intptr_t kNumLT5LookupsIndex = 3;
+ static const intptr_t kNumLT25LookupsIndex = 4;
+ static const intptr_t kNumGT25LookupsIndex = 5;
+ static const intptr_t kHeaderSize = kNumGT25LookupsIndex + 1;
+#endif
static const intptr_t kMetaDataIndex = kHeaderSize;
static const intptr_t kFirstKeyIndex = kHeaderSize + kMetaDataSize;
static const intptr_t kEntrySize = 1 + kPayloadSize;
@@ -491,6 +560,7 @@
table.data_->IsOld() ? Heap::kOld : Heap::kNew));
Copy(table, new_table);
*table.data_ = new_table.Release().raw();
+ NOT_IN_PRODUCT(table.UpdateGrowth(); table.PrintStats();)
}
// Serializes a table by concatenating its entries as an array.
diff --git a/runtime/vm/hash_table_test.cc b/runtime/vm/hash_table_test.cc
index f413932..8e0ac23 100644
--- a/runtime/vm/hash_table_test.cc
+++ b/runtime/vm/hash_table_test.cc
@@ -21,6 +21,7 @@
class TestTraits {
public:
static const char* Name() { return "TestTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const char* key, const Object& obj) {
return String::Cast(obj).Equals(key);
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 0cd9f41..6fd3c3a 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -31,10 +31,10 @@
intptr_t max_old_gen_words,
intptr_t max_external_words)
: isolate_(isolate),
- barrier_(new Monitor()),
- barrier_done_(new Monitor()),
new_space_(this, max_new_gen_semi_words, kNewObjectAlignmentOffset),
old_space_(this, max_old_gen_words, max_external_words),
+ barrier_(new Monitor()),
+ barrier_done_(new Monitor()),
read_only_(false),
gc_new_space_in_progress_(false),
gc_old_space_in_progress_(false),
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 287cbdc..1526424 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -340,16 +340,17 @@
void GetMergedAddressRange(uword* start, uword* end) const;
Isolate* isolate_;
- Monitor* barrier_;
- Monitor* barrier_done_;
// The different spaces used for allocation.
- Scavenger new_space_;
+ ALIGN8 Scavenger new_space_;
PageSpace old_space_;
WeakTable* new_weak_tables_[kNumWeakSelectors];
WeakTable* old_weak_tables_[kNumWeakSelectors];
+ Monitor* barrier_;
+ Monitor* barrier_done_;
+
// GC stats collection.
GCStats stats_;
diff --git a/runtime/vm/instructions.h b/runtime/vm/instructions.h
index a271672..2274bec 100644
--- a/runtime/vm/instructions.h
+++ b/runtime/vm/instructions.h
@@ -17,6 +17,8 @@
#include "vm/instructions_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/instructions_mips.h"
+#elif defined(TARGET_ARCH_DBC)
+#include "vm/instructions_dbc.h"
#else
#error Unknown architecture.
#endif
diff --git a/runtime/vm/instructions_dbc.cc b/runtime/vm/instructions_dbc.cc
new file mode 100644
index 0000000..38b69f4
--- /dev/null
+++ b/runtime/vm/instructions_dbc.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/instructions.h"
+#include "vm/instructions_dbc.h"
+
+#include "vm/assembler.h"
+#include "vm/constants_dbc.h"
+#include "vm/cpu.h"
+#include "vm/object.h"
+
+namespace dart {
+
+CallPattern::CallPattern(uword pc, const Code& code)
+ : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
+ end_(pc),
+ ic_data_load_end_(0),
+ target_code_pool_index_(-1),
+ ic_data_(ICData::Handle()) {
+ UNIMPLEMENTED();
+}
+
+
+int CallPattern::DeoptCallPatternLengthInInstructions() {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int CallPattern::DeoptCallPatternLengthInBytes() {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+NativeCallPattern::NativeCallPattern(uword pc, const Code& code)
+ : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
+ end_(pc),
+ native_function_pool_index_(-1),
+ target_code_pool_index_(-1) {
+ UNIMPLEMENTED();
+}
+
+
+RawCode* NativeCallPattern::target() const {
+ return reinterpret_cast<RawCode*>(
+ object_pool_.ObjectAt(target_code_pool_index_));
+}
+
+
+void NativeCallPattern::set_target(const Code& new_target) const {
+ object_pool_.SetObjectAt(target_code_pool_index_, new_target);
+ // No need to flush the instruction cache, since the code is not modified.
+}
+
+
+NativeFunction NativeCallPattern::native_function() const {
+ return reinterpret_cast<NativeFunction>(
+ object_pool_.RawValueAt(native_function_pool_index_));
+}
+
+
+void NativeCallPattern::set_native_function(NativeFunction func) const {
+ object_pool_.SetRawValueAt(native_function_pool_index_,
+ reinterpret_cast<uword>(func));
+}
+
+
+// Decodes a load sequence ending at 'end' (the last instruction of the load
+// sequence is the instruction before the one at end). Returns a pointer to
+// the first instruction in the sequence. Returns the register being loaded
+// and the loaded object in the output parameters 'reg' and 'obj'
+// respectively.
+uword InstructionPattern::DecodeLoadObject(uword end,
+ const ObjectPool& object_pool,
+ Register* reg,
+ Object* obj) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+// Decodes a load sequence ending at 'end' (the last instruction of the load
+// sequence is the instruction before the one at end). Returns a pointer to
+// the first instruction in the sequence. Returns the register being loaded
+// and the loaded immediate value in the output parameters 'reg' and 'value'
+// respectively.
+uword InstructionPattern::DecodeLoadWordImmediate(uword end,
+ Register* reg,
+ intptr_t* value) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+// Decodes a load sequence ending at 'end' (the last instruction of the load
+// sequence is the instruction before the one at end). Returns a pointer to
+// the first instruction in the sequence. Returns the register being loaded
+// and the index in the pool being read from in the output parameters 'reg'
+// and 'index' respectively.
+uword InstructionPattern::DecodeLoadWordFromPool(uword end,
+ Register* reg,
+ intptr_t* index) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+bool DecodeLoadObjectFromPoolOrThread(uword pc,
+ const Code& code,
+ Object* obj) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+RawICData* CallPattern::IcData() {
+ UNIMPLEMENTED();
+ return ICData::null();
+}
+
+
+RawCode* CallPattern::TargetCode() const {
+ return reinterpret_cast<RawCode*>(
+ object_pool_.ObjectAt(target_code_pool_index_));
+}
+
+
+void CallPattern::SetTargetCode(const Code& target_code) const {
+ object_pool_.SetObjectAt(target_code_pool_index_, target_code);
+}
+
+
+void CallPattern::InsertDeoptCallAt(uword pc, uword target_address) {
+ UNIMPLEMENTED();
+}
+
+
+SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code)
+ : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
+ cache_pool_index_(-1),
+ stub_pool_index_(-1) {
+ UNIMPLEMENTED();
+}
+
+
+RawObject* SwitchableCallPattern::cache() const {
+ return reinterpret_cast<RawCode*>(
+ object_pool_.ObjectAt(cache_pool_index_));
+}
+
+
+void SwitchableCallPattern::SetCache(const MegamorphicCache& cache) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(cache_pool_index_)).IsICData());
+ object_pool_.SetObjectAt(cache_pool_index_, cache);
+}
+
+
+void SwitchableCallPattern::SetLookupStub(const Code& lookup_stub) const {
+ ASSERT(Object::Handle(object_pool_.ObjectAt(stub_pool_index_)).IsCode());
+ object_pool_.SetObjectAt(stub_pool_index_, lookup_stub);
+}
+
+
+ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {
+ USE(pc_);
+}
+
+
+bool ReturnPattern::IsValid() const {
+ UNIMPLEMENTED();
+ return false;
+}
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/instructions_dbc.h b/runtime/vm/instructions_dbc.h
new file mode 100644
index 0000000..5eb0c6e
--- /dev/null
+++ b/runtime/vm/instructions_dbc.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2016, 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.
+// Classes that describe assembly patterns as used by inline caches.
+
+#ifndef VM_INSTRUCTIONS_DBC_H_
+#define VM_INSTRUCTIONS_DBC_H_
+
+#ifndef VM_INSTRUCTIONS_H_
+#error Do not include instructions_dbc.h directly; use instructions.h instead.
+#endif
+
+#include "vm/constants_dbc.h"
+#include "vm/native_entry.h"
+#include "vm/object.h"
+
+namespace dart {
+
+class InstructionPattern : public AllStatic {
+ public:
+ // Decodes a load sequence ending at 'end' (the last instruction of the
+ // load sequence is the instruction before the one at end). Returns the
+ // address of the first instruction in the sequence. Returns the register
+ // being loaded and the loaded object in the output parameters 'reg' and
+ // 'obj' respectively.
+ static uword DecodeLoadObject(uword end,
+ const ObjectPool& object_pool,
+ Register* reg,
+ Object* obj);
+
+ // Decodes a load sequence ending at 'end' (the last instruction of the
+ // load sequence is the instruction before the one at end). Returns the
+ // address of the first instruction in the sequence. Returns the register
+ // being loaded and the loaded immediate value in the output parameters
+ // 'reg' and 'value' respectively.
+ static uword DecodeLoadWordImmediate(uword end,
+ Register* reg,
+ intptr_t* value);
+
+ // Decodes a load sequence ending at 'end' (the last instruction of the
+ // load sequence is the instruction before the one at end). Returns the
+ // address of the first instruction in the sequence. Returns the register
+ // being loaded and the index in the pool being read from in the output
+ // parameters 'reg' and 'index' respectively.
+ static uword DecodeLoadWordFromPool(uword end,
+ Register* reg,
+ intptr_t* index);
+};
+
+
+class CallPattern : public ValueObject {
+ public:
+ CallPattern(uword pc, const Code& code);
+
+ RawICData* IcData();
+
+ RawCode* TargetCode() const;
+ void SetTargetCode(const Code& code) const;
+
+ // This constant length is only valid for inserted call patterns used for
+ // lazy deoptimization. Regular call pattern may vary in length.
+ static int DeoptCallPatternLengthInBytes();
+ static int DeoptCallPatternLengthInInstructions();
+
+ static void InsertDeoptCallAt(uword pc, uword target_address);
+
+ private:
+ const ObjectPool& object_pool_;
+
+ uword end_;
+ uword ic_data_load_end_;
+
+ intptr_t target_code_pool_index_;
+ ICData& ic_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallPattern);
+};
+
+
+class NativeCallPattern : public ValueObject {
+ public:
+ NativeCallPattern(uword pc, const Code& code);
+
+ RawCode* target() const;
+ void set_target(const Code& target) const;
+
+ NativeFunction native_function() const;
+ void set_native_function(NativeFunction target) const;
+
+ private:
+ const ObjectPool& object_pool_;
+
+ uword end_;
+ intptr_t native_function_pool_index_;
+ intptr_t target_code_pool_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeCallPattern);
+};
+
+
+// Instance call that can switch from an IC call to a megamorphic call
+class SwitchableCallPattern : public ValueObject {
+ public:
+ SwitchableCallPattern(uword pc, const Code& code);
+
+ RawObject* cache() const;
+ void SetCache(const MegamorphicCache& cache) const;
+ void SetLookupStub(const Code& stub) const;
+
+ private:
+ const ObjectPool& object_pool_;
+ intptr_t cache_pool_index_;
+ intptr_t stub_pool_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
+};
+
+
+class ReturnPattern : public ValueObject {
+ public:
+ explicit ReturnPattern(uword pc);
+
+ static const int kLengthInBytes = 0;
+
+ int pattern_length_in_bytes() const {
+ UNIMPLEMENTED();
+ return kLengthInBytes;
+ }
+
+ bool IsValid() const;
+
+ private:
+ const uword pc_;
+};
+
+} // namespace dart
+
+#endif // VM_INSTRUCTIONS_DBC_H_
diff --git a/runtime/vm/instructions_x64.cc b/runtime/vm/instructions_x64.cc
index 3fa610a..950fd16 100644
--- a/runtime/vm/instructions_x64.cc
+++ b/runtime/vm/instructions_x64.cc
@@ -25,35 +25,44 @@
ASSERT(code.ContainsInstructionAt(pc));
uint8_t* bytes = reinterpret_cast<uint8_t*>(pc);
+
COMPILE_ASSERT(PP == R15);
- if (((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0x9f)) ||
- ((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0x87)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0xa7)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0x9f)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0x97))) {
- intptr_t index = IndexFromPPLoad(pc + 3);
- const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
- if (pool.InfoAt(index) == ObjectPool::kTaggedObject) {
- *obj = pool.ObjectAt(index);
- return true;
+ if ((bytes[0] == 0x49) || (bytes[0] == 0x4d)) {
+ if ((bytes[1] == 0x8b) || (bytes[1] == 0x3b)) { // movq, cmpq
+ if ((bytes[2] & 0xc7) == (0x80 | (PP & 7))) { // [r15+disp32]
+ intptr_t index = IndexFromPPLoad(pc + 3);
+ const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
+ if (pool.InfoAt(index) == ObjectPool::kTaggedObject) {
+ *obj = pool.ObjectAt(index);
+ return true;
+ }
+ }
+ if ((bytes[2] & 0xc7) == (0x40 | (PP & 7))) { // [r15+disp8]
+ intptr_t index = IndexFromPPLoadDisp8(pc + 3);
+ const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
+ if (pool.InfoAt(index) == ObjectPool::kTaggedObject) {
+ *obj = pool.ObjectAt(index);
+ return true;
+ }
+ }
}
}
+
COMPILE_ASSERT(THR == R14);
- if (((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0x86)) ||
- ((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0xb6)) ||
- ((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0x96)) ||
- ((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0x9e)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0x9e)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0xa6))) {
- int32_t offset = *reinterpret_cast<int32_t*>(pc + 3);
- return Thread::ObjectAtOffset(offset, obj);
+ if ((bytes[0] == 0x49) || (bytes[0] == 0x4d)) {
+ if ((bytes[1] == 0x8b) || (bytes[1] == 0x3b)) { // movq, cmpq
+ if ((bytes[2] & 0xc7) == (0x80 | (THR & 7))) { // [r14+disp32]
+ int32_t offset = *reinterpret_cast<int32_t*>(pc + 3);
+ return Thread::ObjectAtOffset(offset, obj);
+ }
+ if ((bytes[2] & 0xc7) == (0x40 | (THR & 7))) { // [r14+disp8]
+ uint8_t offset = *reinterpret_cast<uint8_t*>(pc + 3);
+ return Thread::ObjectAtOffset(offset, obj);
+ }
+ }
}
- if (((bytes[0] == 0x41) && (bytes[1] == 0xff) && (bytes[2] == 0x76)) ||
- ((bytes[0] == 0x49) && (bytes[1] == 0x3b) && (bytes[2] == 0x66)) ||
- ((bytes[0] == 0x49) && (bytes[1] == 0x8b) && (bytes[2] == 0x46)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0x5e)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0x66)) ||
- ((bytes[0] == 0x4d) && (bytes[1] == 0x8b) && (bytes[2] == 0x6e))) {
+ if (((bytes[0] == 0x41) && (bytes[1] == 0xff) && (bytes[2] == 0x76))) {
+ // push [r14+disp8]
uint8_t offset = *reinterpret_cast<uint8_t*>(pc + 3);
return Thread::ObjectAtOffset(offset, obj);
}
diff --git a/runtime/vm/instructions_x64.h b/runtime/vm/instructions_x64.h
index 5d7616d..8f1c073 100644
--- a/runtime/vm/instructions_x64.h
+++ b/runtime/vm/instructions_x64.h
@@ -22,6 +22,7 @@
intptr_t IndexFromPPLoad(uword start);
+intptr_t IndexFromPPLoadDisp8(uword start);
// Template class for all instruction pattern classes.
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index c68f277..3869329 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -33,7 +33,7 @@
"Propagate IC data from unoptimized to optimized IC calls.");
DEFINE_FLAG(bool, two_args_smi_icd, true,
"Generate special IC stubs for two args Smi operations");
-DEFINE_FLAG(bool, unbox_numeric_fields, true,
+DEFINE_FLAG(bool, unbox_numeric_fields, !USING_DBC,
"Support unboxed double and float32x4 fields.");
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, support_externalizable_strings);
@@ -1651,12 +1651,14 @@
RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const {
- Integer& result = Integer::Handle();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Integer& result = Integer::Handle(zone);
switch (op_kind()) {
case Token::kNEGATE:
result = value.ArithmeticOp(Token::kMUL,
- Smi::Handle(Smi::New(-1)),
+ Smi::Handle(zone, Smi::New(-1)),
Heap::kOld);
break;
@@ -1680,7 +1682,7 @@
// specialized instructions that use this value under this assumption.
return Integer::null();
}
- result ^= result.CheckAndCanonicalize(NULL);
+ result ^= result.CheckAndCanonicalize(thread, NULL);
}
return result.raw();
@@ -1689,7 +1691,9 @@
RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left,
const Integer& right) const {
- Integer& result = Integer::Handle();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Integer& result = Integer::Handle(zone);
switch (op_kind()) {
case Token::kTRUNCDIV:
@@ -1738,7 +1742,7 @@
// specialized instructions that use this value under this assumption.
return Integer::null();
}
- result ^= result.CheckAndCanonicalize(NULL);
+ result ^= result.CheckAndCanonicalize(thread, NULL);
}
return result.raw();
@@ -2586,6 +2590,28 @@
}
+Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) {
+ CompileType* in_type = left()->Type();
+ intptr_t cid = in_type->ToCid();
+ if (cid == kDynamicCid) return this;
+
+ const ZoneGrowableArray<intptr_t>& data = cid_results();
+ const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
+ for (intptr_t i = 0; i < data.length(); i += 2) {
+ if (data[i] == cid) {
+ return (data[i + 1] == true_result)
+ ? flow_graph->GetConstant(Bool::True())
+ : flow_graph->GetConstant(Bool::False());
+ }
+ }
+
+ // TODO(sra): Handle misses if the instruction is not deoptimizing.
+ // TODO(sra): Handle nullable input, possibly canonicalizing to a compare
+ // against `null`.
+ return this;
+}
+
+
Instruction* GuardFieldClassInstr::Canonicalize(FlowGraph* flow_graph) {
if (field().guarded_cid() == kDynamicCid) {
return NULL; // Nothing to guard.
@@ -2766,9 +2792,14 @@
void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ Bind(compiler->GetJumpLabel(this));
if (!compiler->is_optimizing()) {
+#if !defined(TARGET_ARCH_DBC)
+ // TODO(vegorov) re-enable edge counters on DBC if we consider them
+ // beneficial for the quality of the optimized bytecode.
if (compiler->NeedsEdgeCounter(this)) {
compiler->EmitEdgeCounter(preorder_number());
}
+#endif
+
// The deoptimization descriptor points after the edge counter code for
// uniformity with ARM and MIPS, where we can reuse pattern matching
// code that matches backwards from the end of the pattern.
@@ -2968,10 +2999,23 @@
void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+#if defined(TARGET_ARCH_DBC)
+ // On DBC the action of poping the TOS value and then pushing it
+ // after all intermediates are poped is folded into a special
+ // bytecode (DropR). On other architectures this is handled by
+ // instruction prologue/epilogues.
+ ASSERT(!compiler->is_optimizing());
+ if ((InputCount() != 0) && HasTemp()) {
+ __ DropR(num_temps());
+ } else {
+ __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0));
+ }
+#else
ASSERT(!compiler->is_optimizing());
// Assert that register assignment is correct.
ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg()));
__ Drop(num_temps());
+#endif // defined(TARGET_ARCH_DBC)
}
@@ -2996,6 +3040,8 @@
}
+// DBC does not use specialized inline cache stubs for smi operations.
+#if !defined(TARGET_ARCH_DBC)
static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
if (!FLAG_two_args_smi_icd) {
return 0;
@@ -3007,6 +3053,7 @@
default: return NULL;
}
}
+#endif
void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -3023,6 +3070,8 @@
} else {
call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw());
}
+
+#if !defined(TARGET_ARCH_DBC)
if (compiler->is_optimizing() && HasICData()) {
ASSERT(HasICData());
if (ic_data()->NumberOfUsedChecks() > 0) {
@@ -3096,6 +3145,44 @@
*call_ic_data);
}
}
+#else
+ // Emit smi fast path instruction. If fast-path succeeds it skips the next
+ // instruction otherwise it falls through.
+ if (function_name().raw() == Symbols::Plus().raw()) {
+ __ AddTOS();
+ } else if (function_name().raw() == Symbols::EqualOperator().raw()) {
+ __ EqualTOS();
+ } else if (function_name().raw() == Symbols::LAngleBracket().raw()) {
+ __ LessThanTOS();
+ } else if (function_name().raw() == Symbols::RAngleBracket().raw()) {
+ __ GreaterThanTOS();
+ } else if (function_name().raw() == Symbols::BitAnd().raw()) {
+ __ BitAndTOS();
+ } else if (function_name().raw() == Symbols::BitOr().raw()) {
+ __ BitOrTOS();
+ } else if (function_name().raw() == Symbols::Star().raw()) {
+ __ MulTOS();
+ }
+
+ const intptr_t call_ic_data_kidx = __ AddConstant(*call_ic_data);
+ switch (call_ic_data->NumArgsTested()) {
+ case 1:
+ __ InstanceCall(ArgumentCount(), call_ic_data_kidx);
+ break;
+ case 2:
+ __ InstanceCall2(ArgumentCount(), call_ic_data_kidx);
+ break;
+ case 3:
+ __ InstanceCall3(ArgumentCount(), call_ic_data_kidx);
+ break;
+ default:
+ UNIMPLEMENTED();
+ break;
+ }
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall,
+ deopt_id(),
+ token_pos());
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -3118,6 +3205,10 @@
return true;
}
+
+// DBC does not support optimizing compiler and thus doesn't emit
+// PolymorphicInstanceCallInstr.
+#if !defined(TARGET_ARCH_DBC)
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(ic_data().NumArgsTested() == 1);
if (!with_checks()) {
@@ -3141,6 +3232,7 @@
locs(),
complete());
}
+#endif
LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone,
@@ -3150,6 +3242,7 @@
void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+#if !defined(TARGET_ARCH_DBC)
const ICData* call_ic_data = NULL;
if (!FLAG_propagate_ic_data || !compiler->is_optimizing() ||
(ic_data() == NULL)) {
@@ -3182,6 +3275,20 @@
argument_names(),
locs(),
*call_ic_data);
+#else
+ const Array& arguments_descriptor =
+ (ic_data() == NULL) ?
+ Array::Handle(ArgumentsDescriptor::New(ArgumentCount(),
+ argument_names())) :
+ Array::Handle(ic_data()->arguments_descriptor());
+ const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
+
+ __ PushConstant(function());
+ __ StaticCall(ArgumentCount(), argdesc_kidx);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall,
+ deopt_id(),
+ token_pos());
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -3191,7 +3298,11 @@
dst_type(),
dst_name(),
locs());
+
+ // DBC does not use LocationSummaries in the same way as other architectures.
+#if !defined(TARGET_ARCH_DBC)
ASSERT(locs()->in(0).reg() == locs()->out(0).reg());
+#endif
}
@@ -3302,11 +3413,6 @@
}
-static bool BindsToSmiConstant(Value* value) {
- return value->BindsToConstant() && value->BoundConstant().IsSmi();
-}
-
-
ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left,
Value* new_right) {
return new EqualityCompareInstr(token_pos(),
@@ -3374,9 +3480,17 @@
}
+#if !defined(TARGET_ARCH_DBC)
+static bool BindsToSmiConstant(Value* value) {
+ return value->BindsToConstant() && value->BoundConstant().IsSmi();
+}
+#endif
+
+
bool IfThenElseInstr::Supports(ComparisonInstr* comparison,
Value* v1,
Value* v2) {
+#if !defined(TARGET_ARCH_DBC)
bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2);
if (comparison->IsStrictCompare()) {
// Strict comparison with number checks calls a stub and is not supported
@@ -3389,6 +3503,9 @@
return false;
}
return is_smi_result;
+#else
+ return false;
+#endif // !defined(TARGET_ARCH_DBC)
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 6e16c31..1536cf4 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -140,6 +140,9 @@
// Create non-nullable Int type.
static CompileType Int();
+ // Create non-nullable Smi type.
+ static CompileType Smi();
+
// Create non-nullable String type.
static CompileType String();
@@ -3047,6 +3050,8 @@
virtual CompileType ComputeType() const;
+ virtual Definition* Canonicalize(FlowGraph* flow_graph);
+
virtual bool CanDeoptimize() const {
return GetDeoptId() != Thread::kNoDeoptId;
}
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index c7591b5..2c7d44e 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1075,7 +1075,14 @@
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ LoadTaggedClassIdMayBeSmi(result, object);
+ const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
+ if (CompileType::Smi().IsAssignableTo(value_type) ||
+ value_type.IsTypeParameter()) {
+ __ LoadTaggedClassIdMayBeSmi(result, object);
+ } else {
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ }
}
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 452b6ba..f627e6e 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -932,8 +932,14 @@
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
-
- __ LoadTaggedClassIdMayBeSmi(result, object);
+ const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
+ if (CompileType::Smi().IsAssignableTo(value_type) ||
+ value_type.IsTypeParameter()) {
+ __ LoadTaggedClassIdMayBeSmi(result, object);
+ } else {
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ }
}
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
new file mode 100644
index 0000000..293d239
--- /dev/null
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -0,0 +1,703 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/intermediate_language.h"
+
+#include "vm/cpu.h"
+#include "vm/compiler.h"
+#include "vm/dart_entry.h"
+#include "vm/flow_graph.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/flow_graph_range_analysis.h"
+#include "vm/locations.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+#include "vm/simulator.h"
+#include "vm/stack_frame.h"
+#include "vm/stub_code.h"
+#include "vm/symbols.h"
+
+#define __ compiler->assembler()->
+
+namespace dart {
+
+DECLARE_FLAG(bool, emit_edge_counters);
+DECLARE_FLAG(int, optimization_counter_threshold);
+
+// List of instructions that are still unimplemented by DBC backend.
+#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
+ M(Stop) \
+ M(IndirectGoto) \
+ M(LoadCodeUnits) \
+ M(InstanceOf) \
+ M(LoadUntagged) \
+ M(AllocateUninitializedContext) \
+ M(BinaryInt32Op) \
+ M(UnarySmiOp) \
+ M(UnaryDoubleOp) \
+ M(SmiToDouble) \
+ M(Int32ToDouble) \
+ M(MintToDouble) \
+ M(DoubleToInteger) \
+ M(DoubleToSmi) \
+ M(DoubleToDouble) \
+ M(DoubleToFloat) \
+ M(FloatToDouble) \
+ M(UnboxedConstant) \
+ M(CheckEitherNonSmi) \
+ M(BinaryDoubleOp) \
+ M(MathUnary) \
+ M(MathMinMax) \
+ M(Box) \
+ M(Unbox) \
+ M(BoxInt64) \
+ M(CaseInsensitiveCompareUC16) \
+ M(BinaryMintOp) \
+ M(ShiftMintOp) \
+ M(UnaryMintOp) \
+ M(StringToCharCode) \
+ M(StringFromCharCode) \
+ M(InvokeMathCFunction) \
+ M(MergedMath) \
+ M(GuardFieldClass) \
+ M(GuardFieldLength) \
+ M(IfThenElse) \
+ M(BinaryFloat32x4Op) \
+ M(Simd32x4Shuffle) \
+ M(Simd32x4ShuffleMix) \
+ M(Simd32x4GetSignMask) \
+ M(Float32x4Constructor) \
+ M(Float32x4Zero) \
+ M(Float32x4Splat) \
+ M(Float32x4Comparison) \
+ M(Float32x4MinMax) \
+ M(Float32x4Scale) \
+ M(Float32x4Sqrt) \
+ M(Float32x4ZeroArg) \
+ M(Float32x4Clamp) \
+ M(Float32x4With) \
+ M(Float32x4ToInt32x4) \
+ M(Int32x4Constructor) \
+ M(Int32x4BoolConstructor) \
+ M(Int32x4GetFlag) \
+ M(Int32x4Select) \
+ M(Int32x4SetFlag) \
+ M(Int32x4ToFloat32x4) \
+ M(BinaryInt32x4Op) \
+ M(TestCids) \
+ M(BinaryFloat64x2Op) \
+ M(Float64x2Zero) \
+ M(Float64x2Constructor) \
+ M(Float64x2Splat) \
+ M(Float32x4ToFloat64x2) \
+ M(Float64x2ToFloat32x4) \
+ M(Simd64x2Shuffle) \
+ M(Float64x2ZeroArg) \
+ M(Float64x2OneArg) \
+ M(ExtractNthOutput) \
+ M(BinaryUint32Op) \
+ M(ShiftUint32Op) \
+ M(UnaryUint32Op) \
+ M(UnboxedIntConverter) \
+ M(GrowRegExpStack) \
+ M(BoxInteger32) \
+ M(UnboxInteger32) \
+ M(CheckedSmiOp) \
+ M(CheckArrayBound) \
+ M(CheckSmi) \
+ M(LoadClassId) \
+ M(CheckClassId) \
+ M(CheckClass) \
+ M(BinarySmiOp) \
+ M(TestSmi) \
+ M(RelationalOp) \
+ M(EqualityCompare) \
+ M(LoadIndexed) \
+// Location summaries actually are not used by the unoptimizing DBC compiler
+// because we don't allocate any registers.
+static LocationSummary* CreateLocationSummary(Zone* zone,
+ intptr_t num_inputs,
+ bool has_result) {
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs = new(zone) LocationSummary(
+ zone, num_inputs, kNumTemps, LocationSummary::kNoCall);
+ for (intptr_t i = 0; i < num_inputs; i++) {
+ locs->set_in(i, Location::RequiresRegister());
+ }
+ if (has_result) {
+ locs->set_out(0, Location::RequiresRegister());
+ }
+ return locs;
+}
+
+
+#define DEFINE_MAKE_LOCATION_SUMMARY(Name, In, Out) \
+ LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \
+ const { \
+ return CreateLocationSummary(zone, In, Out); \
+ } \
+
+#define EMIT_NATIVE_CODE(Name, In, Out) \
+ DEFINE_MAKE_LOCATION_SUMMARY(Name, In, Out); \
+ void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) \
+
+#define DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \
+ LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \
+ const { \
+ UNIMPLEMENTED(); \
+ return NULL; \
+ } \
+
+#define DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \
+ void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \
+ UNIMPLEMENTED(); \
+ }
+
+#define DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(Name) \
+ void Name##Instr::EmitBranchCode(FlowGraphCompiler*, BranchInstr*) { \
+ UNIMPLEMENTED(); \
+ } \
+ Condition Name##Instr::EmitComparisonCode(FlowGraphCompiler*, \
+ BranchLabels) { \
+ UNIMPLEMENTED(); \
+ return EQ; \
+ }
+
+#define DEFINE_UNIMPLEMENTED(Name) \
+ DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \
+ DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \
+
+FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED)
+
+#undef DEFINE_UNIMPLEMENTED
+
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestCids)
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestSmi)
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(RelationalOp)
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(EqualityCompare)
+
+
+DEFINE_MAKE_LOCATION_SUMMARY(AssertAssignable, 2, true);
+
+
+EMIT_NATIVE_CODE(AssertBoolean, 1, true) {
+ __ AssertBoolean(Isolate::Current()->type_checks() ? 1 : 0);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(),
+ token_pos());
+}
+
+
+LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(Zone* zone,
+ bool optimizing) const {
+ return MakeCallSummary(zone);
+}
+
+
+void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+EMIT_NATIVE_CODE(CheckStackOverflow, 0, false) {
+ __ CheckStack();
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
+ Thread::kNoDeoptId,
+ token_pos());
+}
+
+
+EMIT_NATIVE_CODE(PushArgument, 1, false) {
+ if (compiler->is_optimizing()) {
+ __ Push(locs()->in(0).reg());
+ }
+}
+
+
+EMIT_NATIVE_CODE(LoadLocal, 0, false) {
+ ASSERT(!compiler->is_optimizing());
+ ASSERT(local().index() != 0);
+ __ Push((local().index() > 0) ? (-local().index()) : (-local().index() - 1));
+}
+
+
+EMIT_NATIVE_CODE(StoreLocal, 0, false) {
+ ASSERT(!compiler->is_optimizing());
+ ASSERT(local().index() != 0);
+ if (HasTemp()) {
+ __ StoreLocal(
+ (local().index() > 0) ? (-local().index()) : (-local().index() - 1));
+ } else {
+ __ PopLocal(
+ (local().index() > 0) ? (-local().index()) : (-local().index() - 1));
+ }
+}
+
+
+EMIT_NATIVE_CODE(Constant, 0, true) {
+ const intptr_t kidx = __ AddConstant(value());
+ if (compiler->is_optimizing()) {
+ __ LoadConstant(locs()->out(0).reg(), kidx);
+ } else {
+ __ PushConstant(kidx);
+ }
+}
+
+
+EMIT_NATIVE_CODE(Return, 1, false) {
+ __ ReturnTOS();
+}
+
+
+EMIT_NATIVE_CODE(StoreStaticField, 1, false) {
+ const intptr_t kidx = __ AddConstant(field());
+ __ StoreStaticTOS(kidx);
+}
+
+
+EMIT_NATIVE_CODE(LoadStaticField, 1, true) {
+ const intptr_t kidx = __ AddConstant(StaticField());
+ __ PushStatic(kidx);
+}
+
+
+EMIT_NATIVE_CODE(InitStaticField, 0, false) {
+ ASSERT(!compiler->is_optimizing());
+ __ InitStaticTOS();
+}
+
+
+EMIT_NATIVE_CODE(ClosureCall, 0, false) {
+ intptr_t argument_count = ArgumentCount();
+ const Array& arguments_descriptor =
+ Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
+ argument_names()));
+ const intptr_t argdesc_kidx =
+ compiler->assembler()->AddConstant(arguments_descriptor);
+ __ StaticCall(argument_count, argdesc_kidx);
+
+ compiler->RecordSafepoint(locs());
+ // Marks either the continuation point in unoptimized code or the
+ // deoptimization point in optimized code, after call.
+ const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id());
+ if (compiler->is_optimizing()) {
+ compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos());
+ }
+ // Add deoptimization continuation point after the call and before the
+ // arguments are removed.
+ // In optimized code this descriptor is needed for exception handling.
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
+ deopt_id_after,
+ token_pos());
+}
+
+
+static void EmitBranchOnCondition(FlowGraphCompiler* compiler,
+ Condition true_condition,
+ BranchLabels labels) {
+ if (labels.fall_through == labels.false_label) {
+ // If the next block is the false successor, fall through to it.
+ __ Jump(labels.true_label);
+ } else {
+ // If the next block is not the false successor, branch to it.
+ __ Jump(labels.false_label);
+
+ // Fall through or jump to the true successor.
+ if (labels.fall_through != labels.true_label) {
+ __ Jump(labels.true_label);
+ }
+ }
+}
+
+
+Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+ BranchLabels labels) {
+ ASSERT((kind() == Token::kNE_STRICT) ||
+ (kind() == Token::kEQ_STRICT));
+ const Bytecode::Opcode eq_op = needs_number_check() ?
+ Bytecode::kIfEqStrictNumTOS : Bytecode::kIfEqStrictTOS;
+ const Bytecode::Opcode ne_op = needs_number_check() ?
+ Bytecode::kIfNeStrictNumTOS : Bytecode::kIfNeStrictTOS;
+
+ if (kind() == Token::kEQ_STRICT) {
+ __ Emit((labels.fall_through == labels.false_label) ? eq_op : ne_op);
+ } else {
+ __ Emit((labels.fall_through == labels.false_label) ? ne_op : eq_op);
+ }
+
+ if (needs_number_check() && token_pos().IsReal()) {
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
+ Thread::kNoDeoptId,
+ token_pos());
+ }
+ return EQ;
+}
+
+
+void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+ BranchInstr* branch) {
+ ASSERT((kind() == Token::kEQ_STRICT) ||
+ (kind() == Token::kNE_STRICT));
+
+ BranchLabels labels = compiler->CreateBranchLabels(branch);
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+EMIT_NATIVE_CODE(StrictCompare, 2, true) {
+ ASSERT((kind() == Token::kEQ_STRICT) ||
+ (kind() == Token::kNE_STRICT));
+
+ Label is_true, is_false;
+ BranchLabels labels = { &is_true, &is_false, &is_false };
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ EmitBranchOnCondition(compiler, true_condition, labels);
+ Label done;
+ __ Bind(&is_false);
+ __ PushConstant(Bool::False());
+ __ Jump(&done);
+ __ Bind(&is_true);
+ __ PushConstant(Bool::True());
+ __ Bind(&done);
+}
+
+
+LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ comparison()->InitializeLocationSummary(zone, opt);
+ // Branches don't produce a result.
+ comparison()->locs()->set_out(0, Location::NoLocation());
+ return comparison()->locs();
+}
+
+
+void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ comparison()->EmitBranchCode(compiler, this);
+}
+
+
+EMIT_NATIVE_CODE(Goto, 0, false) {
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
+ // We can fall through if the successor is the next block in the list.
+ // Otherwise, we need a jump.
+ if (!compiler->CanFallThroughTo(successor())) {
+ __ Jump(compiler->GetJumpLabel(successor()));
+ }
+}
+
+
+EMIT_NATIVE_CODE(CreateArray, 2, true) {
+ __ CreateArrayTOS();
+}
+
+
+EMIT_NATIVE_CODE(StoreIndexed, 3, false) {
+ ASSERT(class_id() == kArrayCid);
+ __ StoreIndexedTOS();
+}
+
+
+EMIT_NATIVE_CODE(StringInterpolate, 0, false) {
+ const intptr_t kArgumentCount = 1;
+ const Array& arguments_descriptor = Array::Handle(
+ ArgumentsDescriptor::New(kArgumentCount, Object::null_array()));
+ __ PushConstant(CallFunction());
+ const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
+ __ StaticCall(kArgumentCount, argdesc_kidx);
+}
+
+
+EMIT_NATIVE_CODE(NativeCall, 0, false) {
+ SetupNative();
+
+ const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
+
+ ASSERT(!link_lazily());
+ const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
+ const intptr_t target_kidx =
+ __ object_pool_wrapper().FindImmediate(label.address());
+ const intptr_t argc_tag_kidx =
+ __ object_pool_wrapper().FindImmediate(static_cast<uword>(argc_tag));
+ __ PushConstant(target_kidx);
+ __ PushConstant(argc_tag_kidx);
+ if (is_bootstrap_native()) {
+ __ NativeBootstrapCall();
+ } else {
+ __ NativeCall();
+ }
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ Thread::kNoDeoptId,
+ token_pos());
+}
+
+
+EMIT_NATIVE_CODE(AllocateObject, 0, true) {
+ if (ArgumentCount() == 1) {
+ __ PushConstant(cls());
+ __ AllocateT();
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ Thread::kNoDeoptId,
+ token_pos());
+ } else {
+ const intptr_t kidx = __ AddConstant(cls());
+ __ Allocate(kidx);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ Thread::kNoDeoptId,
+ token_pos());
+ }
+}
+
+
+EMIT_NATIVE_CODE(StoreInstanceField, 2, false) {
+ ASSERT(!HasTemp());
+ ASSERT(offset_in_bytes() % kWordSize == 0);
+ if (compiler->is_optimizing()) {
+ const Register value = locs()->in(1).reg();
+ const Register instance = locs()->in(0).reg();
+ __ StoreField(instance, offset_in_bytes() / kWordSize, value);
+ } else {
+ __ StoreFieldTOS(offset_in_bytes() / kWordSize);
+ }
+}
+
+
+EMIT_NATIVE_CODE(LoadField, 1, true) {
+ ASSERT(offset_in_bytes() % kWordSize == 0);
+ __ LoadFieldTOS(offset_in_bytes() / kWordSize);
+}
+
+
+EMIT_NATIVE_CODE(BooleanNegate, 1, true) {
+ __ BooleanNegateTOS();
+}
+
+
+EMIT_NATIVE_CODE(AllocateContext, 0, false) {
+ __ AllocateContext(num_context_variables());
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ Thread::kNoDeoptId,
+ token_pos());
+}
+
+
+EMIT_NATIVE_CODE(CloneContext, 0, false) {
+ __ CloneContext();
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ Thread::kNoDeoptId,
+ token_pos());
+}
+
+
+EMIT_NATIVE_CODE(CatchBlockEntry, 0, false) {
+ __ Bind(compiler->GetJumpLabel(this));
+ compiler->AddExceptionHandler(catch_try_index(),
+ try_index(),
+ compiler->assembler()->CodeSize(),
+ catch_handler_types_,
+ needs_stacktrace());
+ __ MoveSpecial(-exception_var().index()-1,
+ Simulator::kExceptionSpecialIndex);
+ __ MoveSpecial(-stacktrace_var().index()-1,
+ Simulator::kStacktraceSpecialIndex);
+ __ SetFrame(compiler->StackSize());
+}
+
+
+EMIT_NATIVE_CODE(Throw, 0, false) {
+ __ Throw(0);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(),
+ token_pos());
+ __ Trap();
+}
+
+
+EMIT_NATIVE_CODE(ReThrow, 0, false) {
+ compiler->SetNeedsStacktrace(catch_try_index());
+ __ Throw(1);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(),
+ token_pos());
+ __ Trap();
+}
+
+EMIT_NATIVE_CODE(InstantiateType, 1, true) {
+ __ InstantiateType(__ AddConstant(type()));
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(),
+ token_pos());
+}
+
+EMIT_NATIVE_CODE(InstantiateTypeArguments, 1, true) {
+ __ InstantiateTypeArgumentsTOS(
+ type_arguments().IsRawInstantiatedRaw(type_arguments().Length()),
+ __ AddConstant(type_arguments()));
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(),
+ token_pos());
+}
+
+
+void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ DebugStep();
+ compiler->AddCurrentDescriptor(stub_kind_, Thread::kNoDeoptId, token_pos());
+}
+
+
+void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ if (!compiler->CanFallThroughTo(normal_entry())) {
+ __ Jump(compiler->GetJumpLabel(normal_entry()));
+ }
+}
+
+
+LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
+ LocationSummary* result = new(zone) LocationSummary(
+ zone, 0, 0, LocationSummary::kCall);
+ result->set_out(0, Location::RequiresRegister());
+ return result;
+}
+
+
+CompileType BinaryUint32OpInstr::ComputeType() const {
+ return CompileType::Int();
+}
+
+
+CompileType ShiftUint32OpInstr::ComputeType() const {
+ return CompileType::Int();
+}
+
+
+CompileType UnaryUint32OpInstr::ComputeType() const {
+ return CompileType::Int();
+}
+
+
+static const intptr_t kMintShiftCountLimit = 63;
+
+
+bool ShiftMintOpInstr::has_shift_count_check() const {
+ return !RangeUtils::IsWithin(
+ right()->definition()->range(), 0, kMintShiftCountLimit);
+}
+
+
+CompileType LoadIndexedInstr::ComputeType() const {
+ switch (class_id_) {
+ case kArrayCid:
+ case kImmutableArrayCid:
+ return CompileType::Dynamic();
+
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return CompileType::FromCid(kDoubleCid);
+ case kTypedDataFloat32x4ArrayCid:
+ return CompileType::FromCid(kFloat32x4Cid);
+ case kTypedDataInt32x4ArrayCid:
+ return CompileType::FromCid(kInt32x4Cid);
+ case kTypedDataFloat64x2ArrayCid:
+ return CompileType::FromCid(kFloat64x2Cid);
+
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ case kOneByteStringCid:
+ case kTwoByteStringCid:
+ return CompileType::FromCid(kSmiCid);
+
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ return CompileType::Int();
+
+ default:
+ UNREACHABLE();
+ return CompileType::Dynamic();
+ }
+}
+
+
+Representation LoadIndexedInstr::representation() const {
+ switch (class_id_) {
+ case kArrayCid:
+ case kImmutableArrayCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ case kOneByteStringCid:
+ case kTwoByteStringCid:
+ return kTagged;
+ case kTypedDataInt32ArrayCid:
+ return kUnboxedInt32;
+ case kTypedDataUint32ArrayCid:
+ return kUnboxedUint32;
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return kUnboxedDouble;
+ case kTypedDataInt32x4ArrayCid:
+ return kUnboxedInt32x4;
+ case kTypedDataFloat32x4ArrayCid:
+ return kUnboxedFloat32x4;
+ case kTypedDataFloat64x2ArrayCid:
+ return kUnboxedFloat64x2;
+ default:
+ UNREACHABLE();
+ return kTagged;
+ }
+}
+
+
+Representation StoreIndexedInstr::RequiredInputRepresentation(
+ intptr_t idx) const {
+ // Array can be a Dart object or a pointer to external data.
+ if (idx == 0) return kNoRepresentation; // Flexible input representation.
+ if (idx == 1) return kTagged; // Index is a smi.
+ ASSERT(idx == 2);
+ switch (class_id_) {
+ case kArrayCid:
+ case kOneByteStringCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ return kTagged;
+ case kTypedDataInt32ArrayCid:
+ return kUnboxedInt32;
+ case kTypedDataUint32ArrayCid:
+ return kUnboxedUint32;
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return kUnboxedDouble;
+ case kTypedDataFloat32x4ArrayCid:
+ return kUnboxedFloat32x4;
+ case kTypedDataInt32x4ArrayCid:
+ return kUnboxedInt32x4;
+ case kTypedDataFloat64x2ArrayCid:
+ return kUnboxedFloat64x2;
+ default:
+ UNREACHABLE();
+ return kTagged;
+ }
+}
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 8cae087..44d16ed 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -953,19 +953,25 @@
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- Label done;
-
- // We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
- // a conditional move instead, and requires an additional register---because
- // it is slower, probably due to branch prediction usually working just fine
- // in this case.
- ASSERT(result != object);
- __ movl(result, Immediate(kSmiCid << 1));
- __ testl(object, Immediate(kSmiTagMask));
- __ j(EQUAL, &done, Assembler::kNearJump);
- __ LoadClassId(result, object);
- __ SmiTag(result);
- __ Bind(&done);
+ const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
+ if (CompileType::Smi().IsAssignableTo(value_type) ||
+ value_type.IsTypeParameter()) {
+ // We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
+ // a conditional move instead, and requires an additional register---because
+ // it is slower, probably due to branch prediction usually working just fine
+ // in this case.
+ ASSERT(result != object);
+ Label done;
+ __ movl(result, Immediate(kSmiCid << 1));
+ __ testl(object, Immediate(kSmiTagMask));
+ __ j(EQUAL, &done, Assembler::kNearJump);
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ __ Bind(&done);
+ } else {
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ }
}
@@ -2669,6 +2675,12 @@
const intptr_t value = Smi::Cast(constant).Value();
ASSERT((0 < value) && (value < kCountLimit));
if (shift_left->can_overflow()) {
+ if (value == 1) {
+ // Use overflow flag.
+ __ shll(left, Immediate(1));
+ __ j(OVERFLOW, deopt);
+ return;
+ }
// Check for overflow.
Register temp = locs.temp(0).reg();
__ movl(temp, left);
@@ -2772,6 +2784,12 @@
UNIMPLEMENTED();
}
+
+static bool IsSmiValue(const Object& constant, intptr_t value) {
+ return constant.IsSmi() && (Smi::Cast(constant).Value() == value);
+}
+
+
LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
@@ -2815,12 +2833,16 @@
summary->set_out(0, Location::SameAsFirstInput());
return summary;
} else if (op_kind() == Token::kSHL) {
- const intptr_t kNumTemps = can_overflow() ? 1 : 0;
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ // Shift-by-1 overflow checking can use flags, otherwise we need a temp.
+ const bool shiftBy1 =
+ (right_constant != NULL) && IsSmiValue(right_constant->value(), 1);
+ const intptr_t kNumTemps = (can_overflow() && !shiftBy1) ? 1 : 0;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
- if (can_overflow()) {
+ if (kNumTemps == 1) {
summary->set_temp(0, Location::RequiresRegister());
}
summary->set_out(0, Location::SameAsFirstInput());
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index a8595a8..7bbfb55 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1135,7 +1135,14 @@
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register object = locs()->in(0).reg();
Register result = locs()->out(0).reg();
- __ LoadTaggedClassIdMayBeSmi(result, object);
+ const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
+ if (CompileType::Smi().IsAssignableTo(value_type) ||
+ value_type.IsTypeParameter()) {
+ __ LoadTaggedClassIdMayBeSmi(result, object);
+ } else {
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ }
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 8253b0c..87b1f2e 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -926,19 +926,25 @@
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- Label load, done;
-
- // We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
- // a conditional move instead---because it is slower, probably due to
- // branch prediction usually working just fine in this case.
- __ testq(object, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, &load, Assembler::kNearJump);
- __ LoadImmediate(result, Immediate(Smi::RawValue(kSmiCid)));
- __ jmp(&done);
- __ Bind(&load);
- __ LoadClassId(result, object);
- __ SmiTag(result);
- __ Bind(&done);
+ const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
+ if (CompileType::Smi().IsAssignableTo(value_type) ||
+ value_type.IsTypeParameter()) {
+ // We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
+ // a conditional move instead---because it is slower, probably due to
+ // branch prediction usually working just fine in this case.
+ Label load, done;
+ __ testq(object, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &load, Assembler::kNearJump);
+ __ LoadImmediate(result, Immediate(Smi::RawValue(kSmiCid)));
+ __ jmp(&done);
+ __ Bind(&load);
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ __ Bind(&done);
+ } else {
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ }
}
@@ -2689,6 +2695,12 @@
const intptr_t value = Smi::Cast(constant).Value();
ASSERT((0 < value) && (value < kCountLimit));
if (shift_left->can_overflow()) {
+ if (value == 1) {
+ // Use overflow flag.
+ __ shlq(left, Immediate(1));
+ __ j(OVERFLOW, deopt);
+ return;
+ }
// Check for overflow.
Register temp = locs.temp(0).reg();
__ movq(temp, left);
@@ -2928,6 +2940,10 @@
Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
}
+static bool IsSmiValue(const Object& constant, intptr_t value) {
+ return constant.IsSmi() && (Smi::Cast(constant).Value() == value);
+}
+
LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
@@ -2988,12 +3004,15 @@
summary->set_out(0, Location::SameAsFirstInput());
return summary;
} else if (op_kind() == Token::kSHL) {
- const intptr_t kNumTemps = can_overflow() ? 1 : 0;
+ // Shift-by-1 overflow checking can use flags, otherwise we need a temp.
+ const bool shiftBy1 =
+ (right_constant != NULL) && IsSmiValue(right_constant->value(), 1);
+ const intptr_t kNumTemps = (can_overflow() && !shiftBy1) ? 1 : 0;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX));
- if (can_overflow()) {
+ if (kNumTemps == 1) {
summary->set_temp(0, Location::RequiresRegister());
}
summary->set_out(0, Location::SameAsFirstInput());
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index f42d85e..5615e58 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -119,6 +119,9 @@
}
#endif // defined(DART_NO_SNAPSHOT).
+
+// DBC does not use graph intrinsics.
+#if !defined(TARGET_ARCH_DBC)
static void EmitCodeFor(FlowGraphCompiler* compiler,
FlowGraph* graph) {
// The FlowGraph here is constructed by the intrinsics builder methods, and
@@ -154,10 +157,12 @@
}
compiler->assembler()->Comment("Graph intrinsic end");
}
+#endif
bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
FlowGraphCompiler* compiler) {
+#if !defined(TARGET_ARCH_DBC)
ZoneGrowableArray<const ICData*>* ic_data_array =
new ZoneGrowableArray<const ICData*>();
FlowGraphBuilder builder(parsed_function,
@@ -204,6 +209,9 @@
}
EmitCodeFor(compiler, graph);
return true;
+#else
+ return false;
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -235,10 +243,22 @@
default:
break;
}
+
+ // On DBC all graph intrinsics are handled in the same way as non-graph
+ // intrinsics.
+#if defined(TARGET_ARCH_DBC)
+ switch (function.recognized_kind()) {
+ GRAPH_INTRINSICS_LIST(EMIT_CASE)
+ default:
+ break;
+ }
+#endif
+
#undef EMIT_INTRINSIC
}
+#if !defined(TARGET_ARCH_DBC)
static intptr_t CidForRepresentation(Representation rep) {
switch (rep) {
case kUnboxedDouble:
@@ -1138,5 +1158,7 @@
return BuildInvokeMathCFunction(&builder,
MethodRecognizer::kDoubleRound);
}
+#endif // !defined(TARGET_ARCH_DBC)
+
} // namespace dart
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 1a7e07a..54eec6e 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -42,15 +42,21 @@
static void enum_name(Assembler* assembler);
ALL_INTRINSICS_LIST(DECLARE_FUNCTION)
+#if defined(TARGET_ARCH_DBC)
+ // On DBC graph intrinsics are handled in the same way as non-graph ones.
+ GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
+#endif
#undef DECLARE_FUNCTION
+#if !defined(TARGET_ARCH_DBC)
#define DECLARE_FUNCTION(test_class_name, test_function_name, enum_name, fp) \
static bool Build_##enum_name(FlowGraph* flow_graph);
GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
#undef DECLARE_FUNCTION
+#endif
};
} // namespace dart
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 2fec757..78ab5db 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -156,8 +156,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, \
- /* inline_isolate = */ false); \
+ __ MaybeTraceAllocation(cid, R2, &fall_through); \
__ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* R2: requested array length argument. */ \
@@ -193,7 +192,7 @@
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ LoadAllocationStatsAddress(R4, cid, /* inline_isolate = */ false); \
+ __ LoadAllocationStatsAddress(R4, cid); \
__ str(R1, Address(R3, Heap::TopOffset(space))); \
__ AddImmediate(R0, kHeapObjectTag); \
/* Initialize the tags. */ \
@@ -1847,8 +1846,7 @@
Label* failure) {
const Register length_reg = R2;
Label fail;
- __ MaybeTraceAllocation(kOneByteStringCid, R0, failure,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kOneByteStringCid, R0, failure);
__ mov(R8, Operand(length_reg)); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
@@ -1876,7 +1874,7 @@
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ LoadAllocationStatsAddress(R4, cid, /* inline_isolate = */ false);
+ __ LoadAllocationStatsAddress(R4, cid);
__ str(R1, Address(R3, Heap::TopOffset(space)));
__ AddImmediate(R0, kHeapObjectTag);
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index fd0c053..ba2a6f1 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -168,8 +168,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, \
- /* inline_isolate = */ false); \
+ __ MaybeTraceAllocation(cid, R2, &fall_through); \
__ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* R2: requested array length argument. */ \
@@ -207,8 +206,7 @@
/* next object start and initialize the object. */ \
__ str(R1, Address(R3, Heap::TopOffset(space))); \
__ AddImmediate(R0, R0, kHeapObjectTag); \
- __ UpdateAllocationStatsWithSize(cid, R2, space, \
- /* inline_isolate = */ false); \
+ __ UpdateAllocationStatsWithSize(cid, R2, space); \
/* Initialize the tags. */ \
/* R0: new object start as a tagged pointer. */ \
/* R1: new object end address. */ \
@@ -1926,8 +1924,7 @@
Label* failure) {
const Register length_reg = R2;
Label fail;
- __ MaybeTraceAllocation(kOneByteStringCid, R0, failure,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kOneByteStringCid, R0, failure);
__ mov(R6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
@@ -1957,8 +1954,7 @@
// next object start and initialize the object.
__ str(R1, Address(R3, Heap::TopOffset(space)));
__ AddImmediate(R0, R0, kHeapObjectTag);
- __ UpdateAllocationStatsWithSize(cid, R2, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, R2, space);
// Initialize the tags.
// R0: new object start as a tagged pointer.
diff --git a/runtime/vm/intrinsifier_dbc.cc b/runtime/vm/intrinsifier_dbc.cc
new file mode 100644
index 0000000..21a3ae0
--- /dev/null
+++ b/runtime/vm/intrinsifier_dbc.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/intrinsifier.h"
+
+#include "vm/assembler.h"
+#include "vm/cpu.h"
+#include "vm/dart_entry.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/regexp_assembler.h"
+#include "vm/symbols.h"
+#include "vm/simulator.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, interpret_irregexp);
+
+intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
+
+#define DEFINE_FUNCTION(test_class_name, test_function_name, enum_name, fp) \
+ void Intrinsifier::enum_name(Assembler* assembler) { \
+ if (Simulator::IsSupportedIntrinsic(Simulator::k##enum_name##Intrinsic)) { \
+ assembler->Intrinsic(Simulator::k##enum_name##Intrinsic); \
+ } \
+ } \
+
+ALL_INTRINSICS_LIST(DEFINE_FUNCTION)
+GRAPH_INTRINSICS_LIST(DEFINE_FUNCTION)
+#undef DEFINE_FUNCTION
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index fc1f3be..fd2bc9f 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -199,8 +199,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, \
- /* inline_isolate = */ false); \
+ __ 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. */ \
@@ -244,8 +243,7 @@
/* next object start and initialize the object. */ \
__ movl(Address(ECX, Heap::TopOffset(space)), EBX); \
__ addl(EAX, Immediate(kHeapObjectTag)); \
- __ UpdateAllocationStatsWithSize(cid, EDI, ECX, space, \
- /* inline_isolate = */ false); \
+ __ UpdateAllocationStatsWithSize(cid, EDI, ECX, space); \
\
/* Initialize the tags. */ \
/* EAX: new object start as a tagged pointer. */ \
@@ -1889,8 +1887,7 @@
Label* ok,
Label* failure,
Register length_reg) {
- __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false);
if (length_reg != EDI) {
__ movl(EDI, length_reg);
}
@@ -1924,8 +1921,7 @@
__ movl(Address(ECX, Heap::TopOffset(space)), EBX);
__ addl(EAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, EDI, ECX, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, EDI, ECX, space);
// Initialize the tags.
// EAX: new object start as a tagged pointer.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 2c13390..e98fc1d 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -150,8 +150,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, \
- /* inline_isolate = */ false); \
+ __ MaybeTraceAllocation(cid, T2, &fall_through); \
__ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* T2: requested array length argument. */ \
@@ -188,8 +187,7 @@
/* next object start and initialize the object. */ \
__ sw(T1, Address(T3, Heap::TopOffset(space))); \
__ AddImmediate(V0, kHeapObjectTag); \
- __ UpdateAllocationStatsWithSize(cid, T2, T4, space, \
- /* inline_isolate = */ false); \
+ __ UpdateAllocationStatsWithSize(cid, T2, T4, space); \
/* Initialize the tags. */ \
/* V0: new object start as a tagged pointer. */ \
/* T1: new object end address. */ \
@@ -1967,8 +1965,7 @@
Label* ok,
Label* failure) {
const Register length_reg = T2;
- __ MaybeTraceAllocation(kOneByteStringCid, V0, failure,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kOneByteStringCid, V0, failure);
__ mov(T6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
@@ -1999,8 +1996,7 @@
__ sw(T1, Address(T3, Heap::TopOffset(space)));
__ AddImmediate(V0, kHeapObjectTag);
- __ UpdateAllocationStatsWithSize(cid, T2, T3, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, T2, T3, space);
// Initialize the tags.
// V0: new object start as a tagged pointer.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 66bc4c2..ab2fa94 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -141,8 +141,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, \
- /* inline_isolate = */ false); \
+ __ MaybeTraceAllocation(cid, &fall_through, false); \
__ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* RDI: requested array length argument. */ \
@@ -186,8 +185,7 @@
/* next object start and initialize the object. */ \
__ movq(Address(R13, Heap::TopOffset(space)), RCX); \
__ addq(RAX, Immediate(kHeapObjectTag)); \
- __ UpdateAllocationStatsWithSize(cid, RDI, space, \
- /* inline_isolate = */ false); \
+ __ UpdateAllocationStatsWithSize(cid, RDI, space); \
/* Initialize the tags. */ \
/* RAX: new object start as a tagged pointer. */ \
/* RCX: new object end address. */ \
@@ -1845,8 +1843,7 @@
Label* ok,
Label* failure,
Register length_reg) {
- __ MaybeTraceAllocation(kOneByteStringCid, failure, false,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kOneByteStringCid, failure, false);
if (length_reg != RDI) {
__ movq(RDI, length_reg);
}
@@ -1879,8 +1876,7 @@
// next object start and initialize the object.
__ movq(Address(R13, Heap::TopOffset(space)), RCX);
__ addq(RAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, RDI, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, RDI, space);
// Initialize the tags.
// RAX: new object start as a tagged pointer.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 51e0c7e..287079a 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -993,6 +993,7 @@
if (lib.LoadInProgress()) {
lib.SetLoaded();
}
+ lib.InitExportedNamesCache();
}
TokenStream::CloseSharedTokenList(this);
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 3250082..8061619 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -381,6 +381,8 @@
return background_compiler_;
}
void set_background_compiler(BackgroundCompiler* value) {
+ // Do not overwrite a background compiler (memory leak).
+ ASSERT((value == NULL) || (background_compiler_ == NULL));
background_compiler_ = value;
}
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
index 8a22c85..b0be614 100644
--- a/runtime/vm/jit_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -1881,71 +1881,6 @@
return TryInlineFloat64x2Method(call, recognized_kind);
}
- if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) {
- ASSERT(call->ArgumentCount() == 3);
- ASSERT(ic_data.NumArgsTested() == 2);
- Definition* value = call->ArgumentAt(0);
- Definition* count = call->ArgumentAt(1);
- Definition* int32_mask = call->ArgumentAt(2);
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
- if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
- return false;
- }
- // We cannot overflow. The input value must be a Smi
- AddCheckSmi(value, call->deopt_id(), call->env(), call);
- AddCheckSmi(count, call->deopt_id(), call->env(), call);
- ASSERT(int32_mask->IsConstant());
- const Integer& mask_literal = Integer::Cast(
- int32_mask->AsConstant()->value());
- const int64_t mask_value = mask_literal.AsInt64Value();
- ASSERT(mask_value >= 0);
- if (mask_value > Smi::kMaxValue) {
- // The result will not be Smi.
- return false;
- }
- BinarySmiOpInstr* left_shift =
- new(Z) BinarySmiOpInstr(Token::kSHL,
- new(Z) Value(value),
- new(Z) Value(count),
- call->deopt_id());
- left_shift->mark_truncating();
- if ((kBitsPerWord == 32) && (mask_value == 0xffffffffLL)) {
- // No BIT_AND operation needed.
- ReplaceCall(call, left_shift);
- } else {
- InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
- BinarySmiOpInstr* bit_and =
- new(Z) BinarySmiOpInstr(Token::kBIT_AND,
- new(Z) Value(left_shift),
- new(Z) Value(int32_mask),
- call->deopt_id());
- ReplaceCall(call, bit_and);
- }
- return true;
- }
-
- if (HasTwoMintOrSmi(ic_data) &&
- HasOnlyOneSmi(ICData::Handle(Z,
- ic_data.AsUnaryClassChecksForArgNr(1)))) {
- if (!FlowGraphCompiler::SupportsUnboxedMints() ||
- ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
- return false;
- }
- ShiftMintOpInstr* left_shift =
- new(Z) ShiftMintOpInstr(Token::kSHL,
- new(Z) Value(value),
- new(Z) Value(count),
- call->deopt_id());
- InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
- BinaryMintOpInstr* bit_and =
- new(Z) BinaryMintOpInstr(Token::kBIT_AND,
- new(Z) Value(left_shift),
- new(Z) Value(int32_mask),
- call->deopt_id());
- ReplaceCall(call, bit_and);
- return true;
- }
- }
return false;
}
@@ -2991,7 +2926,8 @@
// - deoptimize dependent code.
if (Compiler::IsBackgroundCompilation()) {
isolate()->AddDeoptimizingBoxedField(field);
- Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+ Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId,
+ "Unboxing instance field while compiling");
UNREACHABLE();
}
if (FLAG_trace_optimization || FLAG_trace_field_guards) {
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index 8a9499e..5603a1c 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -118,6 +118,8 @@
}
+// DBC does not have an notion of 'address' in its instruction set.
+#if !defined(TARGET_ARCH_DBC)
Address Location::ToStackSlotAddress() const {
const intptr_t index = stack_index();
const Register base = base_reg();
@@ -134,7 +136,7 @@
return Address(base, index * kWordSize);
}
}
-
+#endif
intptr_t Location::ToStackSlotOffset() const {
const intptr_t index = stack_index();
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index 963c4b4..fae87a7 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -341,8 +341,11 @@
return IsStackSlot() || IsDoubleStackSlot() || IsQuadStackSlot();
}
+ // DBC does not have an notion of 'address' in its instruction set.
+#if !defined(TARGET_ARCH_DBC)
// Return a memory operand for stack slot locations.
Address ToStackSlotAddress() const;
+#endif
// Returns the offset from the frame pointer for stack slot locations.
intptr_t ToStackSlotOffset() const;
@@ -650,9 +653,13 @@
void set_out(intptr_t index, Location loc) {
ASSERT(index == 0);
+ // DBC calls are different from call on other architectures so this
+ // assert doesn't make sense.
+#if !defined(TARGET_ARCH_DBC)
ASSERT(!always_calls() ||
(loc.IsMachineRegister() || loc.IsInvalid() ||
loc.IsPairLocation()));
+#endif
output_location_ = loc;
}
diff --git a/runtime/vm/log.cc b/runtime/vm/log.cc
index 91be51d..f5247c7 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -31,6 +31,11 @@
Log* Log::Current() {
Thread* thread = Thread::Current();
+ if (thread == NULL) {
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ return os_thread->log();
+ }
Isolate* isolate = thread->isolate();
if (isolate != NULL && Log::ShouldLogForIsolate(isolate)) {
OSThread* os_thread = thread->os_thread();
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 7efa6e7..a3e0eda 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -41,8 +41,6 @@
V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 2075229300) \
V(_StringBase, _interpolate, StringBaseInterpolate, 1597087225) \
V(_IntegerImplementation, toDouble, IntegerToDouble, 150718448) \
- V(_IntegerImplementation, _leftShiftWithMask32, \
- IntegerLeftShiftWithMask32, 1634465017) \
V(_Double, _add, DoubleAdd, 1190606283) \
V(_Double, _sub, DoubleSub, 1086286468) \
V(_Double, _mul, DoubleMul, 166332351) \
@@ -256,7 +254,7 @@
V(Int32x4List, ., TypedData_Int32x4Array_factory, 504220232) \
V(Float64x2List, ., TypedData_Float64x2Array_factory, 416019673) \
-#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
+#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
V(Uint8List, [], Uint8ArrayGetIndexed, 513704632) \
V(Uint8List, []=, Uint8ArraySetIndexed, 2123520783) \
V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 513704632) \
@@ -310,7 +308,6 @@
MATH_LIB_INTRINSIC_LIST(V) \
TYPED_DATA_LIB_INTRINSIC_LIST(V) \
-
#define ALL_INTRINSICS_LIST(V) \
ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V) \
CORE_INTEGER_LIB_INTRINSIC_LIST(V)
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 88bc411..7035a50 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -25,7 +25,10 @@
#if defined(TESTING) || defined(DEBUG)
-#if defined(USING_SIMULATOR)
+#if defined(TARGET_ARCH_DBC)
+// C-stack is always aligned on DBC because we don't have any native code.
+#define CHECK_STACK_ALIGNMENT
+#elif defined(USING_SIMULATOR)
#define CHECK_STACK_ALIGNMENT { \
uword current_sp = Simulator::Current()->get_register(SPREG); \
ASSERT(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment())); \
@@ -92,7 +95,13 @@
RawObject* ArgAt(int index) const {
ASSERT((index >= 0) && (index < ArgCount()));
- RawObject** arg_ptr = &((*argv_)[-index]);
+#if defined(TARGET_ARCH_DBC)
+ // On DBC stack is growing upwards, in reverse direction from all other
+ // architectures.
+ RawObject** arg_ptr = &(argv_[index]);
+#else
+ RawObject** arg_ptr = &(argv_[-index]);
+#endif
// Tell MemorySanitizer the RawObject* was initialized (by generated code).
MSAN_UNPOISON(arg_ptr, kWordSize);
return *arg_ptr;
@@ -204,6 +213,16 @@
friend class BootstrapNatives;
friend class Simulator;
+#if defined(TARGET_ARCH_DBC)
+ // Allow simulator to create NativeArguments on the stack.
+ NativeArguments(Thread* thread,
+ int argc_tag,
+ RawObject** argv,
+ RawObject** retval)
+ : thread_(thread), argc_tag_(argc_tag), argv_(argv), retval_(retval) {
+ }
+#endif
+
// Since this function is passed a RawObject directly, we need to be
// exceedingly careful when we use it. If there are any other side
// effects in the statement that may cause GC, it could lead to
@@ -235,7 +254,7 @@
Thread* thread_; // Current thread pointer.
intptr_t argc_tag_; // Encodes argument count and invoked native call type.
- RawObject*(*argv_)[]; // Pointer to an array of arguments to runtime call.
+ RawObject** argv_; // Pointer to an array of arguments to runtime call.
RawObject** retval_; // Pointer to the return value area.
};
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index a5c79d3..e1e7e45 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -90,7 +90,8 @@
uword NativeEntry::NativeCallWrapperEntry() {
uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper);
-#if defined(USING_SIMULATOR)
+#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
+ // DBC does not use redirections unlike other simulators.
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments);
#endif
@@ -177,6 +178,8 @@
}
+// DBC does not support lazy native call linking.
+#if !defined(TARGET_ARCH_DBC)
static NativeFunction ResolveNativeFunction(Zone* zone,
const Function& func,
bool* is_bootstrap_native) {
@@ -260,9 +263,10 @@
#endif
call_through_wrapper = !is_bootstrap_native;
- const Code& trampoline = Code::Handle(call_through_wrapper ?
- StubCode::CallNativeCFunction_entry()->code() :
- StubCode::CallBootstrapCFunction_entry()->code());
+ const Code& trampoline =
+ Code::Handle(call_through_wrapper ?
+ StubCode::CallNativeCFunction_entry()->code() :
+ StubCode::CallBootstrapCFunction_entry()->code());
NativeFunction patch_target_function = target_function;
#if defined(USING_SIMULATOR)
@@ -295,6 +299,7 @@
target_function(arguments);
}
}
+#endif // !defined(TARGET_ARCH_DBC)
} // namespace dart
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index 9557073..4be2cc3 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -118,8 +118,11 @@
static void NativeCallWrapper(Dart_NativeArguments args,
Dart_NativeFunction func);
+ // DBC does not support lazy native call linking.
+#if !defined(TARGET_ARCH_DBC)
static uword LinkNativeCallEntry();
static void LinkNativeCall(Dart_NativeArguments args);
+#endif
private:
static void NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2ce486b..cc566b7 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -57,6 +57,7 @@
"Show names of internal classes (e.g. \"OneByteString\") in error messages "
"instead of showing the corresponding interface names (e.g. \"String\")");
DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
+DEFINE_FLAG(bool, use_exp_cache, true, "Use library exported name cache");
DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
"Ignore patch file member signature mismatch.");
@@ -705,6 +706,7 @@
empty_array_,
reinterpret_cast<RawArray*>(address + kHeapObjectTag));
empty_array_->StoreSmi(&empty_array_->raw_ptr()->length_, Smi::New(0));
+ empty_array_->SetCanonical();
}
Smi& smi = Smi::Handle();
@@ -718,6 +720,7 @@
zero_array_->StoreSmi(&zero_array_->raw_ptr()->length_, Smi::New(1));
smi = Smi::New(0);
zero_array_->SetAt(0, smi);
+ zero_array_->SetCanonical();
}
// Allocate and initialize the canonical empty context scope object.
@@ -734,6 +737,7 @@
&empty_context_scope_->raw_ptr()->num_variables_, 0);
empty_context_scope_->StoreNonPointer(
&empty_context_scope_->raw_ptr()->is_implicit_, true);
+ empty_context_scope_->SetCanonical();
}
// Allocate and initialize the canonical empty object pool object.
@@ -749,6 +753,7 @@
reinterpret_cast<RawObjectPool*>(address + kHeapObjectTag));
empty_object_pool_->StoreNonPointer(
&empty_object_pool_->raw_ptr()->length_, 0);
+ empty_object_pool_->SetCanonical();
}
// Allocate and initialize the empty_descriptors instance.
@@ -762,6 +767,7 @@
reinterpret_cast<RawPcDescriptors*>(address + kHeapObjectTag));
empty_descriptors_->StoreNonPointer(&empty_descriptors_->raw_ptr()->length_,
0);
+ empty_descriptors_->SetCanonical();
}
// Allocate and initialize the canonical empty variable descriptor object.
@@ -777,6 +783,7 @@
reinterpret_cast<RawLocalVarDescriptors*>(address + kHeapObjectTag));
empty_var_descriptors_->StoreNonPointer(
&empty_var_descriptors_->raw_ptr()->num_entries_, 0);
+ empty_var_descriptors_->SetCanonical();
}
// Allocate and initialize the canonical empty exception handler info object.
@@ -794,6 +801,7 @@
reinterpret_cast<RawExceptionHandlers*>(address + kHeapObjectTag));
empty_exception_handlers_->StoreNonPointer(
&empty_exception_handlers_->raw_ptr()->num_entries_, 0);
+ empty_exception_handlers_->SetCanonical();
}
// The VM isolate snapshot object table is initialized to an empty array
@@ -2089,6 +2097,7 @@
class ClassFunctionsTraits {
public:
static const char* Name() { return "ClassFunctionsTraits"; }
+ static bool ReportStats() { return false; }
// Called when growing the table.
static bool IsMatch(const Object& a, const Object& b) {
@@ -3040,6 +3049,7 @@
RawObject* Class::Evaluate(const String& expr,
const Array& param_names,
const Array& param_values) const {
+ ASSERT(Thread::Current()->IsMutatorThread());
const Function& eval_func =
Function::Handle(EvaluateHelper(*this, expr, param_names, true));
const Object& result =
@@ -3055,7 +3065,8 @@
return Error::null();
}
if (Compiler::IsBackgroundCompilation()) {
- Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+ Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId,
+ "Class finalization while compiling");
}
ASSERT(thread->IsMutatorThread());
ASSERT(thread != NULL);
@@ -4420,44 +4431,88 @@
}
-RawInstance* Class::LookupCanonicalInstance(Zone* zone,
- const Instance& value,
- intptr_t* index) const {
- ASSERT(this->raw() == value.clazz());
- const Array& constants = Array::Handle(zone, this->constants());
- const intptr_t constants_len = constants.Length();
- // Linear search to see whether this value is already present in the
- // list of canonicalized constants.
- Instance& canonical_value = Instance::Handle(zone);
- while (*index < constants_len) {
- canonical_value ^= constants.At(*index);
- if (canonical_value.IsNull()) {
- break;
- }
- if (value.CanonicalizeEquals(canonical_value)) {
- ASSERT(canonical_value.IsCanonical());
- return canonical_value.raw();
- }
- *index = *index + 1;
+class CanonicalInstanceKey {
+ public:
+ explicit CanonicalInstanceKey(const Instance& key) : key_(key) {
+ ASSERT(!(key.IsString() || key.IsInteger() || key.IsAbstractType()));
}
- return Instance::null();
+ bool Matches(const Instance& obj) const {
+ ASSERT(!(obj.IsString() || obj.IsInteger() || obj.IsAbstractType()));
+ if (key_.CanonicalizeEquals(obj)) {
+ ASSERT(obj.IsCanonical());
+ return true;
+ }
+ return false;
+ }
+ uword Hash() const {
+ return key_.ComputeCanonicalTableHash();
+ }
+ const Instance& key_;
+
+ private:
+ DISALLOW_ALLOCATION();
+};
+
+
+// Traits for looking up Canonical Instances based on a hash of the fields.
+class CanonicalInstanceTraits {
+ public:
+ static const char* Name() { return "CanonicalInstanceTraits"; }
+ static bool ReportStats() { return false; }
+
+ // Called when growing the table.
+ static bool IsMatch(const Object& a, const Object& b) {
+ ASSERT(!(a.IsString() || a.IsInteger() || a.IsAbstractType()));
+ ASSERT(!(b.IsString() || b.IsInteger() || b.IsAbstractType()));
+ return a.raw() == b.raw();
+ }
+ static bool IsMatch(const CanonicalInstanceKey& a, const Object& b) {
+ return a.Matches(Instance::Cast(b));
+ }
+ static uword Hash(const Object& key) {
+ ASSERT(!(key.IsString() || key.IsNumber() || key.IsAbstractType()));
+ ASSERT(key.IsInstance());
+ return Instance::Cast(key).ComputeCanonicalTableHash();
+ }
+ static uword Hash(const CanonicalInstanceKey& key) {
+ return key.Hash();
+ }
+ static RawObject* NewKey(const CanonicalInstanceKey& obj) {
+ return obj.key_.raw();
+ }
+};
+typedef UnorderedHashSet <CanonicalInstanceTraits> CanonicalInstancesSet;
+
+
+RawInstance* Class::LookupCanonicalInstance(Zone* zone,
+ const Instance& value) const {
+ ASSERT(this->raw() == value.clazz());
+ Instance& canonical_value = Instance::Handle(zone);
+ if (this->constants() != Object::empty_array().raw()) {
+ CanonicalInstancesSet constants(zone, this->constants());
+ canonical_value ^= constants.GetOrNull(CanonicalInstanceKey(value));
+ this->set_constants(constants.Release());
+ }
+ return canonical_value.raw();
}
-void Class::InsertCanonicalConstant(intptr_t index,
- const Instance& constant) const {
- // The constant needs to be added to the list. Grow the list if it is full.
- Array& canonical_list = Array::Handle(constants());
- const intptr_t list_len = canonical_list.Length();
- if (index >= list_len) {
- const intptr_t new_length = (list_len == 0) ? 4 : list_len + 4;
- const Array& new_canonical_list =
- Array::Handle(Array::Grow(canonical_list, new_length, Heap::kOld));
- set_constants(new_canonical_list);
- new_canonical_list.SetAt(index, constant);
+RawInstance* Class::InsertCanonicalConstant(Zone* zone,
+ const Instance& constant) const {
+ ASSERT(this->raw() == constant.clazz());
+ Instance& canonical_value = Instance::Handle(zone);
+ if (this->constants() == Object::empty_array().raw()) {
+ CanonicalInstancesSet constants(
+ HashTables::New<CanonicalInstancesSet>(128, Heap::kOld));
+ canonical_value ^= constants.InsertNewOrGet(CanonicalInstanceKey(constant));
+ this->set_constants(constants.Release());
} else {
- canonical_list.SetAt(index, constant);
+ CanonicalInstancesSet constants(Thread::Current()->zone(),
+ this->constants());
+ canonical_value ^= constants.InsertNewOrGet(CanonicalInstanceKey(constant));
+ this->set_constants(constants.Release());
}
+ return canonical_value.raw();
}
@@ -4476,6 +4531,29 @@
}
+void Class::RehashConstants(Zone* zone) const {
+ intptr_t cid = id();
+ if ((cid == kMintCid) || (cid == kBigintCid) || (cid == kDoubleCid)) {
+ // Constants stored as a plain list, no rehashing needed.
+ return;
+ }
+
+ const Array& old_constants = Array::Handle(zone, constants());
+ if (old_constants.Length() == 0) return;
+
+ set_constants(Object::empty_array());
+ CanonicalInstancesSet set(zone, old_constants.raw());
+ Instance& constant = Instance::Handle(zone);
+ CanonicalInstancesSet::Iterator it(&set);
+ while (it.MoveNext()) {
+ constant ^= set.GetKey(it.Current());
+ ASSERT(!constant.IsNull());
+ InsertCanonicalConstant(zone, constant);
+ }
+ set.Release();
+}
+
+
RawUnresolvedClass* UnresolvedClass::New(const LibraryPrefix& library_prefix,
const String& ident,
TokenPosition token_pos) {
@@ -8333,6 +8411,7 @@
class CompressedTokenTraits {
public:
static const char* Name() { return "CompressedTokenTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const Scanner::TokenDescriptor& descriptor,
const Object& key) {
@@ -9263,6 +9342,7 @@
class LibraryUrlTraits {
public:
static const char* Name() { return "LibraryUrlTraits"; }
+ static bool ReportStats() { return false; }
// Called when growing the table.
static bool IsMatch(const Object& a, const Object& b) {
@@ -9312,6 +9392,7 @@
void Library::AddPatchClass(const Class& cls) const {
+ ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(cls.is_patch());
ASSERT(GetPatchClass(String::Handle(cls.Name())) == Class::null());
const GrowableObjectArray& patch_classes =
@@ -9321,6 +9402,7 @@
RawClass* Library::GetPatchClass(const String& name) const {
+ ASSERT(Thread::Current()->IsMutatorThread());
const GrowableObjectArray& patch_classes =
GrowableObjectArray::Handle(this->patch_classes());
Object& obj = Object::Handle();
@@ -9336,6 +9418,7 @@
void Library::RemovePatchClass(const Class& cls) const {
+ ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(cls.is_patch());
const GrowableObjectArray& patch_classes =
GrowableObjectArray::Handle(this->patch_classes());
@@ -9403,6 +9486,7 @@
const String& name,
TokenPosition token_pos) const {
Thread* thread = Thread::Current();
+ ASSERT(thread->IsMutatorThread());
Zone* zone = thread->zone();
const String& metaname = String::Handle(zone, Symbols::New(thread, name));
const Field& field = Field::Handle(zone,
@@ -9490,6 +9574,7 @@
RawField* Library::GetMetadataField(const String& metaname) const {
+ ASSERT(Thread::Current()->IsMutatorThread());
const GrowableObjectArray& metadata =
GrowableObjectArray::Handle(this->metadata());
Field& entry = Field::Handle();
@@ -9574,6 +9659,7 @@
class StringEqualsTraits {
public:
static const char* Name() { return "StringEqualsTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
return String::Cast(a).Equals(String::Cast(b));
@@ -9595,8 +9681,15 @@
*obj = cache.GetOrNull(name, &present);
// Mutator compiler thread may add entries and therefore
// change 'resolved_names()' while running a background compilation;
- // do not ASSERT that 'resolved_names()' has not changed.
- cache.Release();
+ // ASSERT that 'resolved_names()' has not changed only in mutator.
+#if defined(DEBUG)
+ if (Thread::Current()->IsMutatorThread()) {
+ ASSERT(cache.Release().raw() == resolved_names());
+ } else {
+ // Release must be called in debug mode.
+ cache.Release();
+ }
+#endif
return present;
}
@@ -9606,8 +9699,7 @@
// the name does not resolve to anything in this library scope.
void Library::AddToResolvedNamesCache(const String& name,
const Object& obj) const {
- ASSERT(!Compiler::IsBackgroundCompilation());
- if (!FLAG_use_lib_cache) {
+ if (!FLAG_use_lib_cache || Compiler::IsBackgroundCompilation()) {
return;
}
ResolvedNamesMap cache(resolved_names());
@@ -9616,12 +9708,64 @@
}
+bool Library::LookupExportedNamesCache(const String& name,
+ Object* obj) const {
+ ASSERT(FLAG_use_exp_cache);
+ if (exported_names() == Array::null()) {
+ return false;
+ }
+ ResolvedNamesMap cache(exported_names());
+ bool present = false;
+ *obj = cache.GetOrNull(name, &present);
+ // Mutator compiler thread may add entries and therefore
+ // change 'exported_names()' while running a background compilation;
+ // do not ASSERT that 'exported_names()' has not changed.
+#if defined(DEBUG)
+ if (Thread::Current()->IsMutatorThread()) {
+ ASSERT(cache.Release().raw() == exported_names());
+ } else {
+ // Release must be called in debug mode.
+ cache.Release();
+ }
+#endif
+ return present;
+}
+
+void Library::AddToExportedNamesCache(const String& name,
+ const Object& obj) const {
+ if (!FLAG_use_exp_cache || Compiler::IsBackgroundCompilation()) {
+ return;
+ }
+ if (exported_names() == Array::null()) {
+ AllocateExportedNamesCache();
+ }
+ ResolvedNamesMap cache(exported_names());
+ cache.UpdateOrInsert(name, obj);
+ StorePointer(&raw_ptr()->exported_names_, cache.Release().raw());
+}
+
+
void Library::InvalidateResolvedName(const String& name) const {
- Object& entry = Object::Handle();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Object& entry = Object::Handle(zone);
if (LookupResolvedNamesCache(name, &entry)) {
// TODO(koda): Support deleted sentinel in snapshots and remove only 'name'.
InvalidateResolvedNamesCache();
}
+ // When a new name is added to a library, we need to invalidate all
+ // caches that contain an entry for this name. If the name was previously
+ // looked up but could not be resolved, the cache contains a null entry.
+ GrowableObjectArray& libs = GrowableObjectArray::Handle(
+ zone, thread->isolate()->object_store()->libraries());
+ Library& lib = Library::Handle(zone);
+ intptr_t num_libs = libs.Length();
+ for (intptr_t i = 0; i < num_libs; i++) {
+ lib ^= libs.At(i);
+ if (lib.LookupExportedNamesCache(name, &entry)) {
+ lib.InitExportedNamesCache();
+ }
+ }
}
@@ -9631,6 +9775,19 @@
}
+// Invalidate all exported names caches in the isolate.
+void Library::InvalidateExportedNamesCaches() {
+ GrowableObjectArray& libs = GrowableObjectArray::Handle(
+ Isolate::Current()->object_store()->libraries());
+ Library& lib = Library::Handle();
+ intptr_t num_libs = libs.Length();
+ for (intptr_t i = 0; i < num_libs; i++) {
+ lib ^= libs.At(i);
+ lib.InitExportedNamesCache();
+ }
+}
+
+
void Library::GrowDictionary(const Array& dict, intptr_t dict_size) const {
// TODO(iposva): Avoid exponential growth.
intptr_t new_dict_size = dict_size * 2;
@@ -9665,7 +9822,7 @@
void Library::AddObject(const Object& obj, const String& name) const {
- ASSERT(!Compiler::IsBackgroundCompilation());
+ ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(obj.IsClass() ||
obj.IsFunction() ||
obj.IsField() ||
@@ -9706,42 +9863,45 @@
// Lookup a name in the library's re-export namespace.
// This lookup can occur from two different threads: background compiler and
// mutator thread.
-RawObject* Library::LookupReExport(const String& name) const {
- if (HasExports()) {
- const bool is_background_compiler = Compiler::IsBackgroundCompilation();
- Array& exports = Array::Handle();
- if (is_background_compiler) {
- exports = this->exports2();
- // Break potential export cycle while looking up name.
- StorePointer(&raw_ptr()->exports2_, Object::empty_array().raw());
- } else {
- exports = this->exports();
- // Break potential export cycle while looking up name.
- StorePointer(&raw_ptr()->exports_, Object::empty_array().raw());
- }
- Namespace& ns = Namespace::Handle();
- Object& obj = Object::Handle();
- for (int i = 0; i < exports.Length(); i++) {
- ns ^= exports.At(i);
- obj = ns.Lookup(name);
- if (!obj.IsNull()) {
- // The Lookup call above may return a setter x= when we are looking
- // for the name x. Make sure we only return when a matching name
- // is found.
- String& obj_name = String::Handle(obj.DictionaryName());
- if (Field::IsSetterName(obj_name) == Field::IsSetterName(name)) {
- break;
- }
- }
- }
- if (is_background_compiler) {
- StorePointer(&raw_ptr()->exports2_, exports.raw());
- } else {
- StorePointer(&raw_ptr()->exports_, exports.raw());
- }
+RawObject* Library::LookupReExport(const String& name,
+ ZoneGrowableArray<intptr_t>* trail) const {
+ if (!HasExports()) {
+ return Object::null();
+ }
+
+ if (trail == NULL) {
+ trail = new ZoneGrowableArray<intptr_t>();
+ }
+ Object& obj = Object::Handle();
+ if (FLAG_use_exp_cache && LookupExportedNamesCache(name, &obj)) {
return obj.raw();
}
- return Object::null();
+
+ const intptr_t lib_id = this->index();
+ ASSERT(lib_id >= 0); // We use -1 to indicate that a cycle was found.
+ trail->Add(lib_id);
+ const Array& exports = Array::Handle(this->exports());
+ Namespace& ns = Namespace::Handle();
+ for (int i = 0; i < exports.Length(); i++) {
+ ns ^= exports.At(i);
+ obj = ns.Lookup(name, trail);
+ if (!obj.IsNull()) {
+ // The Lookup call above may return a setter x= when we are looking
+ // for the name x. Make sure we only return when a matching name
+ // is found.
+ String& obj_name = String::Handle(obj.DictionaryName());
+ if (Field::IsSetterName(obj_name) == Field::IsSetterName(name)) {
+ break;
+ }
+ }
+ }
+ bool in_cycle = (trail->RemoveLast() < 0);
+ if (FLAG_use_exp_cache &&
+ !in_cycle &&
+ !Compiler::IsBackgroundCompilation()) {
+ AddToExportedNamesCache(name, obj);
+ }
+ return obj.raw();
}
@@ -9785,8 +9945,10 @@
bool Library::RemoveObject(const Object& obj, const String& name) const {
- ASSERT(!Compiler::IsBackgroundCompilation());
- Object& entry = Object::Handle();
+ Thread* thread = Thread::Current();
+ ASSERT(thread->IsMutatorThread());
+ Zone* zone = thread->zone();
+ Object& entry = Object::Handle(zone);
intptr_t index;
entry = LookupEntry(name, &index);
@@ -9794,12 +9956,12 @@
return false;
}
- const Array& dict = Array::Handle(dictionary());
+ const Array& dict = Array::Handle(zone, dictionary());
dict.SetAt(index, Object::null_object());
intptr_t dict_size = dict.Length() - 1;
// Fix any downstream collisions.
- String& key = String::Handle();
+ String& key = String::Handle(zone);
for (;;) {
index = (index + 1) % dict_size;
entry = dict.At(index);
@@ -9822,9 +9984,10 @@
// Update used count.
intptr_t used_elements = Smi::Value(Smi::RawCast(dict.At(dict_size))) - 1;
- dict.SetAt(dict_size, Smi::Handle(Smi::New(used_elements)));
+ dict.SetAt(dict_size, Smi::Handle(zone, Smi::New(used_elements)));
InvalidateResolvedNamesCache();
+ InvalidateExportedNamesCaches();
return true;
}
@@ -9860,6 +10023,7 @@
RawArray* Library::LoadedScripts() const {
+ ASSERT(Thread::Current()->IsMutatorThread());
// We compute the list of loaded scripts lazily. The result is
// cached in loaded_scripts_.
if (loaded_scripts() == Array::null()) {
@@ -10190,7 +10354,6 @@
void Library::DropDependencies() const {
StorePointer(&raw_ptr()->imports_, Array::null());
StorePointer(&raw_ptr()->exports_, Array::null());
- StorePointer(&raw_ptr()->exports2_, Array::null());
}
@@ -10223,7 +10386,6 @@
intptr_t num_exports = exports.Length();
exports = Array::Grow(exports, num_exports + 1);
StorePointer(&raw_ptr()->exports_, exports.raw());
- StorePointer(&raw_ptr()->exports2_, exports.raw());
exports.SetAt(num_exports, ns);
}
@@ -10238,6 +10400,7 @@
void Library::InitResolvedNamesCache(intptr_t size,
SnapshotReader* reader) const {
+ ASSERT(Thread::Current()->IsMutatorThread());
if (reader == NULL) {
StorePointer(&raw_ptr()->resolved_names_,
HashTables::New<ResolvedNamesMap>(size));
@@ -10250,6 +10413,20 @@
}
+void Library::AllocateExportedNamesCache() const {
+ StorePointer(&raw_ptr()->exported_names_,
+ HashTables::New<ResolvedNamesMap>(16));
+}
+
+
+void Library::InitExportedNamesCache() const {
+ if (exported_names() != Array::null()) {
+ StorePointer(&raw_ptr()->exported_names_,
+ HashTables::New<ResolvedNamesMap>(16));
+ }
+}
+
+
void Library::InitClassDictionary() const {
// TODO(iposva): Find reasonable initial size.
const int kInitialElementCount = 16;
@@ -10276,11 +10453,16 @@
RawLibrary* Library::NewLibraryHelper(const String& url,
bool import_core_lib) {
- const Library& result = Library::Handle(Library::New());
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ ASSERT(thread->IsMutatorThread());
+ const Library& result = Library::Handle(zone, Library::New());
result.StorePointer(&result.raw_ptr()->name_, Symbols::Empty().raw());
result.StorePointer(&result.raw_ptr()->url_, url.raw());
result.StorePointer(&result.raw_ptr()->resolved_names_,
Object::empty_array().raw());
+ result.StorePointer(&result.raw_ptr()->exported_names_,
+ Array::null());
result.StorePointer(&result.raw_ptr()->dictionary_,
Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->metadata_,
@@ -10291,8 +10473,6 @@
Heap::kOld));
result.StorePointer(&result.raw_ptr()->imports_, Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->exports_, Object::empty_array().raw());
- result.StorePointer(&result.raw_ptr()->exports2_,
- Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
result.StorePointer(&result.raw_ptr()->load_error_, Instance::null());
result.set_native_entry_resolver(NULL);
@@ -10310,9 +10490,9 @@
result.InitImportList();
result.AllocatePrivateKey();
if (import_core_lib) {
- const Library& core_lib = Library::Handle(Library::CoreLibrary());
+ const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
- const Namespace& ns = Namespace::Handle(
+ const Namespace& ns = Namespace::Handle(zone,
Namespace::New(core_lib, Object::null_array(), Object::null_array()));
result.AddImport(ns);
}
@@ -10930,10 +11110,10 @@
void Namespace::AddMetadata(const Object& owner, TokenPosition token_pos) {
ASSERT(Field::Handle(metadata_field()).IsNull());
Field& field = Field::Handle(Field::NewTopLevel(Symbols::TopLevel(),
- false, // is_final
- false, // is_const
- owner,
- token_pos));
+ false, // is_final
+ false, // is_const
+ owner,
+ token_pos));
field.set_is_reflectable(false);
field.SetFieldType(Object::dynamic_type());
field.SetStaticValue(Array::empty_array(), true);
@@ -11014,11 +11194,24 @@
// Look up object with given name in library and filter out hidden
// names. Also look up getters and setters.
-RawObject* Namespace::Lookup(const String& name) const {
+RawObject* Namespace::Lookup(const String& name,
+ ZoneGrowableArray<intptr_t>* trail) const {
Zone* zone = Thread::Current()->zone();
const Library& lib = Library::Handle(zone, library());
- intptr_t ignore = 0;
+ if (trail != NULL) {
+ // Look for cycle in reexport graph.
+ for (int i = 0; i < trail->length(); i++) {
+ if (trail->At(i) == lib.index()) {
+ for (int j = i+1; j < trail->length(); j++) {
+ (*trail)[j] = -1;
+ }
+ return Object::null();
+ }
+ }
+ }
+
+ intptr_t ignore = 0;
// Lookup the name in the library's symbols.
Object& obj = Object::Handle(zone, lib.LookupEntry(name, &ignore));
if (!Field::IsGetterName(name) &&
@@ -11040,14 +11233,14 @@
// Library prefixes are not exported.
if (obj.IsNull() || obj.IsLibraryPrefix()) {
// Lookup in the re-exported symbols.
- obj = lib.LookupReExport(name);
+ obj = lib.LookupReExport(name, trail);
if (obj.IsNull() && !Field::IsSetterName(name)) {
// LookupReExport() only returns objects that match the given name.
// If there is no field/func/getter, try finding a setter.
const String& setter_name =
String::Handle(zone, Field::LookupSetterSymbol(name));
if (!setter_name.IsNull()) {
- obj = lib.LookupReExport(setter_name);
+ obj = lib.LookupReExport(setter_name, trail);
}
}
}
@@ -13743,8 +13936,9 @@
Zone* zone = thread->zone();
const char* name = StubCode::NameOfStub(EntryPoint());
ASSERT(name != NULL);
- const String& stub_name = String::Handle(zone, String::New(name));
- return Symbols::FromConcat(thread, Symbols::StubPrefix(), stub_name);
+ char* stub_name = OS::SCreate(zone,
+ "%s%s", Symbols::StubPrefix().ToCString(), name);
+ return Symbols::New(thread, stub_name, strlen(stub_name));
} else if (obj.IsClass()) {
// Allocation stub.
Thread* thread = Thread::Current();
@@ -13800,6 +13994,7 @@
void Code::DisableStubCode() const {
+#if !defined(TARGET_ARCH_DBC)
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(IsAllocationStubCode());
ASSERT(!IsDisabled());
@@ -13807,6 +14002,10 @@
Code::Handle(StubCode::FixAllocationStubTarget_entry()->code());
ASSERT(new_code.instructions()->IsVMHeapObject());
SetActiveInstructions(new_code.instructions());
+#else
+ // DBC does not use allocation stubs.
+ UNIMPLEMENTED();
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -14749,8 +14948,13 @@
{
NoSafepointScope no_safepoint;
// Raw bits compare.
- const intptr_t instance_size = Class::Handle(this->clazz()).instance_size();
+ const intptr_t instance_size = SizeFromClass();
ASSERT(instance_size != 0);
+ const intptr_t other_instance_size = other.SizeFromClass();
+ ASSERT(other_instance_size != 0);
+ if (instance_size != other_instance_size) {
+ return false;
+ }
uword this_addr = reinterpret_cast<uword>(this->raw_ptr());
uword other_addr = reinterpret_cast<uword>(other.raw_ptr());
for (intptr_t offset = Instance::NextFieldOffset();
@@ -14766,6 +14970,24 @@
}
+uword Instance::ComputeCanonicalTableHash() const {
+ ASSERT(!IsNull());
+ NoSafepointScope no_safepoint;
+ const intptr_t instance_size = SizeFromClass();
+ ASSERT(instance_size != 0);
+ uword hash = instance_size;
+ uword this_addr = reinterpret_cast<uword>(this->raw_ptr());
+ for (intptr_t offset = Instance::NextFieldOffset();
+ offset < instance_size;
+ offset += kWordSize) {
+ uword value = reinterpret_cast<uword>(
+ *reinterpret_cast<RawObject**>(this_addr + offset));
+ hash = CombineHashes(hash, value);
+ }
+ return FinalizeHash(hash);
+}
+
+
#if defined(DEBUG)
class CheckForPointers : public ObjectPointerVisitor {
public:
@@ -14788,21 +15010,21 @@
#endif // DEBUG
-bool Instance::CheckAndCanonicalizeFields(Zone* zone,
+bool Instance::CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const {
- const Class& cls = Class::Handle(zone, this->clazz());
- if (cls.id() >= kNumPredefinedCids) {
+ if (GetClassId() >= kNumPredefinedCids) {
// Iterate over all fields, canonicalize numbers and strings, expect all
// other instances to be canonical otherwise report error (return false).
+ Zone* zone = thread->zone();
Object& obj = Object::Handle(zone);
- intptr_t end_field_offset = cls.instance_size() - kWordSize;
+ intptr_t end_field_offset = SizeFromClass() - kWordSize;
for (intptr_t field_offset = 0;
field_offset <= end_field_offset;
field_offset += kWordSize) {
obj = *this->FieldAddrAtOffset(field_offset);
if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
if (obj.IsNumber() || obj.IsString()) {
- obj = Instance::Cast(obj).CheckAndCanonicalize(NULL);
+ obj = Instance::Cast(obj).CheckAndCanonicalize(thread, NULL);
ASSERT(!obj.IsNull());
this->SetFieldAtOffset(field_offset, obj);
} else {
@@ -14825,46 +15047,35 @@
}
-RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
+RawInstance* Instance::CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const {
ASSERT(!IsNull());
if (this->IsCanonical()) {
return this->raw();
}
- Thread* thread = Thread::Current();
- Zone* zone = thread->zone();
- if (!CheckAndCanonicalizeFields(zone, error_str)) {
+ if (!CheckAndCanonicalizeFields(thread, error_str)) {
return Instance::null();
}
+ Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
Instance& result = Instance::Handle(zone);
const Class& cls = Class::Handle(zone, this->clazz());
- intptr_t index = 0;
- result ^= cls.LookupCanonicalInstance(zone, *this, &index);
- if (!result.IsNull()) {
- return result.raw();
- }
{
SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
- // Retry lookup.
- {
- result ^= cls.LookupCanonicalInstance(zone, *this, &index);
+ if (IsNew()) {
+ result ^= cls.LookupCanonicalInstance(zone, *this);
if (!result.IsNull()) {
return result.raw();
}
- }
-
- // The value needs to be added to the list. Grow the list if
- // it is full.
- result ^= this->raw();
- ASSERT((isolate == Dart::vm_isolate()) || !result.InVMHeap());
- if (result.IsNew()) {
+ ASSERT((isolate == Dart::vm_isolate()) || !InVMHeap());
// Create a canonical object in old space.
- result ^= Object::Clone(result, Heap::kOld);
+ result ^= Object::Clone(*this, Heap::kOld);
+ } else {
+ result ^= this->raw();
}
ASSERT(result.IsOld());
result.SetCanonical();
- cls.InsertCanonicalConstant(index, result);
- return result.raw();
+ return cls.InsertCanonicalConstant(zone, result);
}
}
@@ -14945,7 +15156,9 @@
Zone* zone = Thread::Current()->zone();
const Class& cls = Class::Handle(zone, clazz());
if (cls.IsClosureClass()) {
- if (other.IsObjectType() || other.IsDartFunctionType()) {
+ if (other.IsObjectType() ||
+ other.IsDartFunctionType() ||
+ other.IsDartClosureType()) {
return true;
}
Function& other_signature = Function::Handle(zone);
@@ -15302,6 +15515,13 @@
bool AbstractType::IsInstantiated(TrailPtr trail) const {
// AbstractType is an abstract class.
+ // TODO(srdjan) : Remove temporary code.
+NOT_IN_PRODUCT(
+ Profiler::DumpStackTrace(true); // Only native stack trace.
+)
+ if (Compiler::IsBackgroundCompilation()) {
+ UNREACHABLE();
+ }
UNREACHABLE();
return false;
}
@@ -15732,6 +15952,13 @@
}
+bool AbstractType::IsDartClosureType() const {
+ return !IsFunctionType() &&
+ HasResolvedTypeClass() &&
+ (type_class() == Isolate::Current()->object_store()->closure_class());
+}
+
+
bool AbstractType::TypeTest(TypeTestKind test_kind,
const AbstractType& other,
Error* bound_error,
@@ -16509,8 +16736,8 @@
return Object::dynamic_type().raw();
}
// Fast canonical lookup/registry for simple types.
- if (!cls.IsGeneric() && !cls.IsClosureClass()) {
- ASSERT(!IsFunctionType() || cls.IsTypedefClass());
+ if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
+ ASSERT(!IsFunctionType());
type = cls.CanonicalType();
if (type.IsNull()) {
ASSERT(!cls.raw()->IsVMHeapObject() || (isolate == Dart::vm_isolate()));
@@ -17236,7 +17463,9 @@
void BoundedType::set_type(const AbstractType& value) const {
- ASSERT(value.IsFinalized() || value.IsBeingFinalized());
+ ASSERT(value.IsFinalized() ||
+ value.IsBeingFinalized() ||
+ value.IsTypeParameter());
ASSERT(!value.IsMalformed());
StorePointer(&raw_ptr()->type_, value.raw());
}
@@ -17305,8 +17534,8 @@
return bounded_type.raw();
}
const TypeParameter& type_param = TypeParameter::Handle(type_parameter());
- if (instantiated_bounded_type.IsBeingFinalized() ||
- instantiated_upper_bound.IsBeingFinalized() ||
+ if (!instantiated_bounded_type.IsFinalized() ||
+ !instantiated_upper_bound.IsFinalized() ||
(!type_param.CheckBound(instantiated_bounded_type,
instantiated_upper_bound,
bound_error,
@@ -17315,7 +17544,8 @@
bound_error->IsNull())) {
// We cannot determine yet whether the bounded_type is below the
// upper_bound, because one or both of them is still being finalized or
- // uninstantiated.
+ // uninstantiated. For example, instantiated_bounded_type may be the
+ // still unfinalized cloned type parameter of a mixin application class.
ASSERT(instantiated_bounded_type.IsBeingFinalized() ||
instantiated_upper_bound.IsBeingFinalized() ||
!instantiated_bounded_type.IsInstantiated() ||
@@ -17483,7 +17713,8 @@
}
-RawInstance* Number::CheckAndCanonicalize(const char** error_str) const {
+RawInstance* Number::CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const {
intptr_t cid = GetClassId();
switch (cid) {
case kSmiCid:
@@ -17493,10 +17724,9 @@
case kDoubleCid:
return Double::NewCanonical(Double::Cast(*this).value());
case kBigintCid: {
- Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
- if (!CheckAndCanonicalizeFields(zone, error_str)) {
+ if (!CheckAndCanonicalizeFields(thread, error_str)) {
return Instance::null();
}
Bigint& result = Bigint::Handle(zone);
@@ -18249,15 +18479,16 @@
}
-bool Bigint::CheckAndCanonicalizeFields(Zone* zone,
+bool Bigint::CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const {
+ Zone* zone = thread->zone();
// Bool field neg should always be canonical.
ASSERT(Bool::Handle(zone, neg()).IsCanonical());
// Smi field used is canonical by definition.
if (Used() > 0) {
// Canonicalize TypedData field digits.
TypedData& digits_ = TypedData::Handle(zone, digits());
- digits_ ^= digits_.CheckAndCanonicalize(NULL);
+ digits_ ^= digits_.CheckAndCanonicalize(thread, NULL);
ASSERT(!digits_.IsNull());
set_digits(digits_);
} else {
@@ -19229,7 +19460,8 @@
}
-RawInstance* String::CheckAndCanonicalize(const char** error_str) const {
+RawInstance* String::CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const {
if (IsCanonical()) {
return this->raw();
}
@@ -20686,6 +20918,9 @@
}
// Now check if both arrays have the same type arguments.
+ if (GetTypeArguments() == other.GetTypeArguments()) {
+ return true;
+ }
const TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments());
const TypeArguments& other_type_args = TypeArguments::Handle(
other.GetTypeArguments());
@@ -20696,6 +20931,20 @@
}
+uword Array::ComputeCanonicalTableHash() const {
+ ASSERT(!IsNull());
+ intptr_t len = Length();
+ uword hash = len;
+ uword value = reinterpret_cast<uword>(GetTypeArguments());
+ hash = CombineHashes(hash, value);
+ for (intptr_t i = 0; i < len; i++) {
+ value = reinterpret_cast<uword>(At(i));
+ hash = CombineHashes(hash, value);
+ }
+ return FinalizeHash(hash);
+}
+
+
RawArray* Array::New(intptr_t len, Heap::Space space) {
ASSERT(Isolate::Current()->object_store()->array_class() != Class::null());
return New(kClassId, len, space);
@@ -20837,24 +21086,28 @@
}
-bool Array::CheckAndCanonicalizeFields(Zone* zone,
+bool Array::CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const {
- Object& obj = Object::Handle(zone);
- // Iterate over all elements, canonicalize numbers and strings, expect all
- // other instances to be canonical otherwise report error (return false).
- for (intptr_t i = 0; i < Length(); i++) {
- obj = At(i);
- if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
- if (obj.IsNumber() || obj.IsString()) {
- obj = Instance::Cast(obj).CheckAndCanonicalize(NULL);
- ASSERT(!obj.IsNull());
- this->SetAt(i, obj);
- } else {
- ASSERT(error_str != NULL);
- char* chars = OS::SCreate(Thread::Current()->zone(),
- "element at index %" Pd ": %s\n", i, obj.ToCString());
- *error_str = chars;
- return false;
+ intptr_t len = Length();
+ if (len > 0) {
+ Zone* zone = thread->zone();
+ Object& obj = Object::Handle(zone);
+ // Iterate over all elements, canonicalize numbers and strings, expect all
+ // other instances to be canonical otherwise report error (return false).
+ for (intptr_t i = 0; i < len; i++) {
+ obj = At(i);
+ if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
+ if (obj.IsNumber() || obj.IsString()) {
+ obj = Instance::Cast(obj).CheckAndCanonicalize(thread, NULL);
+ ASSERT(!obj.IsNull());
+ this->SetAt(i, obj);
+ } else {
+ ASSERT(error_str != NULL);
+ char* chars = OS::SCreate(
+ zone, "element at index %" Pd ": %s\n", i, obj.ToCString());
+ *error_str = chars;
+ return false;
+ }
}
}
}
@@ -20946,6 +21199,9 @@
// Equivalent to Dart's operator "==" and hashCode.
class DefaultHashTraits {
public:
+ static const char* Name() { return "DefaultHashTraits"; }
+ static bool ReportStats() { return false; }
+
static bool IsMatch(const Object& a, const Object& b) {
if (a.IsNull() || b.IsNull()) {
return (a.IsNull() && b.IsNull());
@@ -21335,6 +21591,17 @@
}
+uword TypedData::ComputeCanonicalTableHash() const {
+ const intptr_t len = this->LengthInBytes();
+ ASSERT(len != 0);
+ uword hash = len;
+ for (intptr_t i = 0; i < len; i++) {
+ hash = CombineHashes(len, GetUint8(i));
+ }
+ return FinalizeHash(hash);
+}
+
+
RawTypedData* TypedData::New(intptr_t class_id,
intptr_t len,
Heap::Space space) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6a2008f..53a22fc 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1213,10 +1213,10 @@
const Bigint& value, intptr_t* index) const;
// The methods above are more efficient than this generic one.
RawInstance* LookupCanonicalInstance(Zone* zone,
- const Instance& value,
- intptr_t* index) const;
+ const Instance& value) const;
- void InsertCanonicalConstant(intptr_t index, const Instance& constant) const;
+ RawInstance* InsertCanonicalConstant(Zone* zone,
+ const Instance& constant) const;
void InsertCanonicalNumber(Zone* zone,
intptr_t index,
const Number& constant) const;
@@ -1224,6 +1224,8 @@
intptr_t FindCanonicalTypeIndex(const AbstractType& needle) const;
RawAbstractType* CanonicalTypeFromIndex(intptr_t idx) const;
+ void RehashConstants(Zone* zone) const;
+
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawClass));
}
@@ -3529,7 +3531,8 @@
void AddObject(const Object& obj, const String& name) const;
void ReplaceObject(const Object& obj, const String& name) const;
bool RemoveObject(const Object& obj, const String& name) const;
- RawObject* LookupReExport(const String& name) const;
+ RawObject* LookupReExport(const String& name,
+ ZoneGrowableArray<intptr_t>* visited = NULL) const;
RawObject* LookupObjectAllowPrivate(const String& name) const;
RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
RawObject* LookupLocalObject(const String& name) const;
@@ -3582,7 +3585,6 @@
// Library imports.
RawArray* imports() const { return raw_ptr()->imports_; }
RawArray* exports() const { return raw_ptr()->exports_; }
- RawArray* exports2() const { return raw_ptr()->exports2_; }
void AddImport(const Namespace& ns) const;
intptr_t num_imports() const { return raw_ptr()->num_imports_; }
RawNamespace* ImportAt(intptr_t index) const;
@@ -3708,12 +3710,19 @@
RawArray* resolved_names() const { return raw_ptr()->resolved_names_; }
void InitResolvedNamesCache(intptr_t size,
SnapshotReader* reader = NULL) const;
- void GrowResolvedNamesCache() const;
+ void AllocateExportedNamesCache() const;
+ void InitExportedNamesCache() const;
+ static void InvalidateExportedNamesCaches();
bool LookupResolvedNamesCache(const String& name, Object* obj) const;
void AddToResolvedNamesCache(const String& name, const Object& obj) const;
void InvalidateResolvedName(const String& name) const;
void InvalidateResolvedNamesCache() const;
+ RawArray* exported_names() const { return raw_ptr()->exported_names_; }
+ bool LookupExportedNamesCache(const String& name, Object* obj) const;
+ void AddToExportedNamesCache(const String& name, const Object& obj) const;
+
+
void InitImportList() const;
void GrowDictionary(const Array& dict, intptr_t dict_size) const;
static RawLibrary* NewLibraryHelper(const String& url,
@@ -3734,6 +3743,7 @@
friend class Bootstrap;
friend class Class;
friend class Debugger;
+ friend class Isolate;
friend class DictionaryIterator;
friend class Namespace;
friend class Object;
@@ -3756,7 +3766,8 @@
}
bool HidesName(const String& name) const;
- RawObject* Lookup(const String& name) const;
+ RawObject* Lookup(const String& name,
+ ZoneGrowableArray<intptr_t>* trail = NULL) const;
static RawNamespace* New(const Library& library,
const Array& show_names,
@@ -5153,16 +5164,26 @@
virtual bool OperatorEquals(const Instance& other) const;
bool IsIdenticalTo(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
+ virtual uword ComputeCanonicalTableHash() const;
+
+ intptr_t SizeFromClass() const {
+#if defined(DEBUG)
+ const Class& cls = Class::Handle(clazz());
+ ASSERT(cls.is_finalized() || cls.is_prefinalized());
+#endif
+ return (clazz()->ptr()->instance_size_in_words_ * kWordSize);
+ }
// Returns Instance::null() if instance cannot be canonicalized.
// Any non-canonical number of string will be canonicalized here.
// An instance cannot be canonicalized if it still contains non-canonical
// instances in its fields.
// Returns error in error_str, pass NULL if an error cannot occur.
- virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
+ virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const;
// Returns true if all fields are OK for canonicalization.
- virtual bool CheckAndCanonicalizeFields(Zone* zone,
+ virtual bool CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const;
RawObject* GetField(const Field& field) const {
@@ -5382,7 +5403,8 @@
virtual RawAbstractType* CloneUninstantiated(
const Class& new_owner, TrailPtr trail = NULL) const;
- virtual RawInstance* CheckAndCanonicalize(const char** error_str) const {
+ virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const {
return Canonicalize();
}
@@ -5485,6 +5507,9 @@
// Check if this type represents the Dart 'Function' type.
bool IsDartFunctionType() const;
+ // Check if this type represents the Dart '_Closure' type.
+ bool IsDartClosureType() const;
+
// Check the subtype relationship.
bool IsSubtypeOf(const AbstractType& other,
Error* bound_error,
@@ -5951,7 +5976,8 @@
RawString* ToString(Heap::Space space) const;
// Numbers are canonicalized differently from other instances/strings.
- virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
+ virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const;
private:
OBJECT_IMPLEMENTATION(Number, Instance);
@@ -5977,6 +6003,10 @@
virtual bool CanonicalizeEquals(const Instance& other) const {
return Equals(other);
}
+ virtual uword ComputeCanonicalTableHash() const {
+ UNREACHABLE();
+ return 0;
+ }
virtual bool Equals(const Instance& other) const;
virtual RawObject* HashCode() const { return raw(); }
@@ -6162,7 +6192,7 @@
virtual int CompareWith(const Integer& other) const;
- virtual bool CheckAndCanonicalizeFields(Zone* zone,
+ virtual bool CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const;
virtual bool FitsIntoSmi() const;
@@ -6254,6 +6284,10 @@
bool BitwiseEqualsToDouble(double value) const;
virtual bool OperatorEquals(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
+ virtual uword ComputeCanonicalTableHash() const {
+ UNREACHABLE();
+ return 0;
+ }
static RawDouble* New(double d, Heap::Space space = Heap::kNew);
@@ -6404,6 +6438,10 @@
virtual bool CanonicalizeEquals(const Instance& other) const {
return Equals(other);
}
+ virtual uword ComputeCanonicalTableHash() const {
+ UNREACHABLE();
+ return 0;
+ }
virtual bool Equals(const Instance& other) const;
intptr_t CompareTo(const String& other) const;
@@ -6411,7 +6449,8 @@
bool StartsWith(const String& other) const;
// Strings are canonicalized using the symbol table.
- virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
+ virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const;
bool IsSymbol() const { return raw()->IsCanonical(); }
@@ -7093,6 +7132,7 @@
}
virtual bool CanonicalizeEquals(const Instance& other) const;
+ virtual uword ComputeCanonicalTableHash() const;
static const intptr_t kBytesPerElement = kWordSize;
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
@@ -7114,7 +7154,7 @@
}
// Returns true if all elements are OK for canonicalization.
- virtual bool CheckAndCanonicalizeFields(Zone* zone,
+ virtual bool CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const;
// Make the array immutable to Dart code by switching the class pointer
@@ -7266,9 +7306,14 @@
UNREACHABLE();
return false;
}
+ virtual uword ComputeCanonicalTableHash() const {
+ UNREACHABLE();
+ return 0;
+ }
// We don't expect a growable object array to be canonicalized.
- virtual RawInstance* CheckAndCanonicalize(const char** error_str) const {
+ virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const {
UNREACHABLE();
return Instance::null();
}
@@ -7442,6 +7487,7 @@
}
virtual bool CanonicalizeEquals(const Instance& other) const;
+ virtual uword ComputeCanonicalTableHash() const;
#define TYPED_GETTER_SETTER(name, type) \
type Get##name(intptr_t byte_offset) const { \
@@ -7957,7 +8003,7 @@
}
// Returns true if all elements are OK for canonicalization.
- virtual bool CheckAndCanonicalizeFields(Zone* zone,
+ virtual bool CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const {
// None of the fields of a closure are instances.
return true;
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 90f9e1d..3cfc25b 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1034,27 +1034,34 @@
return;
}
- // Walk the superclass chain, adding all instance fields.
+ // Add all fields in layout order, from superclass to subclass.
+ GrowableArray<Class*> classes;
Class& cls = Class::Handle(this->clazz());
+ do {
+ cls.Print();
+ classes.Add(&Class::Handle(cls.raw()));
+ cls = cls.SuperClass();
+ } while (!cls.IsNull());
+
+ Array& field_array = Array::Handle();
+ Field& field = Field::Handle();
+ Instance& field_value = Instance::Handle();
{
- Instance& fieldValue = Instance::Handle();
JSONArray jsarr(jsobj, "fields");
- while (!cls.IsNull()) {
- const Array& field_array = Array::Handle(cls.fields());
- Field& field = Field::Handle();
+ for (intptr_t i = classes.length() - 1; i >= 0; i--) {
+ field_array = classes[i]->fields();
if (!field_array.IsNull()) {
- for (intptr_t i = 0; i < field_array.Length(); i++) {
- field ^= field_array.At(i);
+ for (intptr_t j = 0; j < field_array.Length(); j++) {
+ field ^= field_array.At(j);
if (!field.is_static()) {
- fieldValue ^= GetField(field);
+ field_value ^= GetField(field);
JSONObject jsfield(&jsarr);
jsfield.AddProperty("type", "BoundField");
jsfield.AddProperty("decl", field);
- jsfield.AddProperty("value", fieldValue);
+ jsfield.AddProperty("value", field_value);
}
}
}
- cls = cls.SuperClass();
}
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 62718be..aa75ee9 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -21,10 +21,6 @@
DECLARE_FLAG(bool, write_protect_code);
-static RawLibrary* CreateDummyLibrary(const String& library_name) {
- return Library::New(library_name);
-}
-
static RawClass* CreateDummyClass(const String& class_name,
const Script& script) {
@@ -2690,6 +2686,12 @@
}
+#if !defined(TARGET_ARCH_DBC)
+static RawLibrary* CreateDummyLibrary(const String& library_name) {
+ return Library::New(library_name);
+}
+
+
static RawFunction* CreateFunction(const char* name) {
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
@@ -2966,6 +2968,7 @@
EXPECT_EQ(false, iter.MoveNext());
}
+#endif // !defined(TARGET_ARCH_DBC)
static RawClass* CreateTestClass(const char* name) {
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 03540bb..3269b12 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -191,7 +191,7 @@
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM64)
const int kMinimumAlignment = 16;
-#elif defined(TARGET_ARCH_ARM)
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 8;
#else
#error Unsupported architecture.
@@ -212,6 +212,8 @@
const int kMinimumAlignment = 16;
#elif defined(TARGET_ARCH_ARM)
const int kMinimumAlignment = 16;
+#elif defined(TARGET_ARCH_DBC)
+ const int kMinimumAlignment = 16;
#else
#error Unsupported architecture.
#endif
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index edfb890..0fc90c7 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -197,7 +197,8 @@
intptr_t OS::ActivationFrameAlignment() {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM64)
+ defined(TARGET_ARCH_ARM64) || \
+ defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 16;
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
const int kMinimumAlignment = 8;
@@ -217,7 +218,8 @@
intptr_t OS::PreferredCodeAlignment() {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM64)
+ defined(TARGET_ARCH_ARM64) || \
+ defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 32;
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
const int kMinimumAlignment = 16;
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 3393cb0..d2d5576 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -169,6 +169,8 @@
return 16; // iOS simulator
#elif TARGET_ARCH_X64
return 16; // iOS simulator
+#elif TARGET_ARCH_DBC
+ return 16;
#else
#error Unimplemented
#endif
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 87146f6..14446d9 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -5062,18 +5062,22 @@
&Symbols::ClosureParameter(),
&Object::dynamic_type());
- const bool no_explicit_default_values = false;
- ParseFormalParameterList(no_explicit_default_values, false, &func_params);
- ExpectSemicolon();
+ // Mark the current class as a typedef class (by setting its signature
+ // function field to a non-null function) before parsing its formal parameters
+ // so that parsed function types are aware that their owner class is a
+ // typedef class.
Function& signature_function =
Function::Handle(Z, Function::NewSignatureFunction(function_type_alias,
alias_name_pos));
- signature_function.set_result_type(result_type);
- AddFormalParamsToFunction(&func_params, signature_function);
-
// Set the signature function in the function type alias class.
function_type_alias.set_signature_function(signature_function);
+ const bool no_explicit_default_values = false;
+ ParseFormalParameterList(no_explicit_default_values, false, &func_params);
+ ExpectSemicolon();
+ signature_function.set_result_type(result_type);
+ AddFormalParamsToFunction(&func_params, signature_function);
+
if (FLAG_trace_parser) {
OS::Print("TopLevel parsing function type alias '%s'\n",
String::Handle(Z, signature_function.Signature()).ToCString());
@@ -10520,7 +10524,6 @@
}
-// TODO(srdjan): Implement other optimizations.
AstNode* Parser::OptimizeBinaryOpNode(TokenPosition op_pos,
Token::Kind binary_op,
AstNode* lhs,
@@ -10547,20 +10550,6 @@
rhs_literal = lhs_literal;
lhs_literal = temp;
}
- if ((rhs_literal != NULL) &&
- (rhs_literal->literal().IsSmi() || rhs_literal->literal().IsMint())) {
- const int64_t val = Integer::Cast(rhs_literal->literal()).AsInt64Value();
- if ((0 <= val) && (Utils::IsUint(32, val))) {
- if (lhs->IsBinaryOpNode() &&
- (lhs->AsBinaryOpNode()->kind() == Token::kSHL)) {
- // Merge SHL and BIT_AND into one "SHL with mask" node.
- BinaryOpNode* old = lhs->AsBinaryOpNode();
- BinaryOpWithMask32Node* binop = new(Z) BinaryOpWithMask32Node(
- old->token_pos(), old->kind(), old->left(), old->right(), val);
- return binop;
- }
- }
- }
}
if (binary_op == Token::kIFNULL) {
// Handle a ?? b.
@@ -11980,6 +11969,7 @@
class ConstMapKeyEqualsTraits {
public:
static const char* Name() { return "ConstMapKeyEqualsTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
const Array& key1 = Array::Cast(a);
@@ -12063,7 +12053,7 @@
}
const char* error_str = NULL;
Instance& result =
- Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str));
+ Instance::Handle(Z, instance.CheckAndCanonicalize(thread(), &error_str));
if (result.IsNull()) {
ReportError(token_pos, "Invalid const object %s", error_str);
}
@@ -12748,6 +12738,9 @@
if (is_const) {
// Allocate and initialize the const list at compile time.
+ if ((element_list.length() == 0) && list_type_arguments.IsNull()) {
+ return new(Z) LiteralNode(literal_pos, Object::empty_array());
+ }
Array& const_list = Array::ZoneHandle(Z,
Array::New(element_list.length(), Heap::kOld));
const_list.SetTypeArguments(
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index fc83b31..0bb6669 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -146,6 +146,7 @@
sent_selectors_(),
enqueued_functions_(),
fields_to_retain_(),
+ functions_to_retain_(),
classes_to_retain_(),
typeargs_to_retain_(),
types_to_retain_(),
@@ -199,6 +200,7 @@
I->set_compilation_allowed(false);
+ TraceForRetainedFunctions();
DropFunctions();
DropFields();
TraceTypesFromRetainedClasses();
@@ -583,6 +585,10 @@
void Precompiler::AddTypesOf(const Function& function) {
+ if (function.IsNull()) return;
+ if (functions_to_retain_.Lookup(&function) != NULL) return;
+ functions_to_retain_.Insert(&Function::ZoneHandle(Z, function.raw()));
+
AbstractType& type = AbstractType::Handle(Z);
type = function.result_type();
AddType(type);
@@ -1058,6 +1064,7 @@
class NameFunctionsTraits {
public:
static const char* Name() { return "NameFunctionsTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
return a.IsString() && b.IsString() &&
@@ -1209,12 +1216,71 @@
}
-void Precompiler::DropFunctions() {
+void Precompiler::TraceForRetainedFunctions() {
Library& lib = Library::Handle(Z);
Class& cls = Class::Handle(Z);
Array& functions = Array::Handle(Z);
Function& function = Function::Handle(Z);
Function& function2 = Function::Handle(Z);
+ GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+
+ functions = cls.functions();
+ for (intptr_t j = 0; j < functions.Length(); j++) {
+ function ^= functions.At(j);
+ bool retain = function.HasCode();
+ if (!retain && function.HasImplicitClosureFunction()) {
+ // It can happen that all uses of an implicit closure inline their
+ // target function, leaving the target function uncompiled. Keep
+ // the target function anyway so we can enumerate it to bind its
+ // static calls, etc.
+ function2 = function.ImplicitClosureFunction();
+ retain = function2.HasCode();
+ }
+ if (retain) {
+ function.DropUncompiledImplicitClosureFunction();
+ AddTypesOf(function);
+ }
+ }
+ }
+ }
+
+ closures = isolate()->object_store()->closure_functions();
+ for (intptr_t j = 0; j < closures.Length(); j++) {
+ function ^= closures.At(j);
+ bool retain = function.HasCode();
+ if (retain) {
+ AddTypesOf(function);
+
+ cls = function.Owner();
+ AddTypesOf(cls);
+
+ // It can happen that all uses of a function are inlined, leaving
+ // a compiled local function with an uncompiled parent. Retain such
+ // parents and their enclosing classes and libraries.
+ function = function.parent_function();
+ while (!function.IsNull()) {
+ AddTypesOf(function);
+ function = function.parent_function();
+ }
+ }
+ }
+}
+
+
+void Precompiler::DropFunctions() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& functions = Array::Handle(Z);
+ Function& function = Function::Handle(Z);
GrowableObjectArray& retained_functions = GrowableObjectArray::Handle(Z);
GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
String& name = String::Handle(Z);
@@ -1232,19 +1298,10 @@
retained_functions = GrowableObjectArray::New();
for (intptr_t j = 0; j < functions.Length(); j++) {
function ^= functions.At(j);
- bool retain = function.HasCode();
- if (!retain && function.HasImplicitClosureFunction()) {
- // It can happen that all uses of an implicit closure inline their
- // target function, leaving the target function uncompiled. Keep
- // the target function anyway so we can enumerate it to bind its
- // static calls, etc.
- function2 = function.ImplicitClosureFunction();
- retain = function2.HasCode();
- }
+ bool retain = functions_to_retain_.Lookup(&function) != NULL;
+ function.DropUncompiledImplicitClosureFunction();
if (retain) {
retained_functions.Add(function);
- function.DropUncompiledImplicitClosureFunction();
- AddTypesOf(function);
} else {
bool top_level = cls.IsTopLevel();
if (top_level &&
@@ -1276,10 +1333,9 @@
retained_functions = GrowableObjectArray::New();
for (intptr_t j = 0; j < closures.Length(); j++) {
function ^= closures.At(j);
- bool retain = function.HasCode();
+ bool retain = functions_to_retain_.Lookup(&function) != NULL;
if (retain) {
retained_functions.Add(function);
- AddTypesOf(function);
} else {
dropped_function_count_++;
if (FLAG_trace_precompiler) {
@@ -1482,15 +1538,21 @@
retained_constants.Add(constant);
}
}
- if (retained_constants.Length() > 0) {
+ intptr_t cid = cls.id();
+ if ((cid == kMintCid) || (cid == kBigintCid) || (cid == kDoubleCid)) {
+ // Constants stored as a plain list, no rehashing needed.
constants = Array::MakeArray(retained_constants);
cls.set_constants(constants);
} else {
- constants = Object::empty_array().raw();
+ // Rehash.
cls.set_constants(Object::empty_array());
+ for (intptr_t j = 0; j < retained_constants.Length(); j++) {
+ constant ^= retained_constants.At(j);
+ cls.InsertCanonicalConstant(Z, constant);
+ }
}
- if (constants.Length() > 0) {
+ if (retained_constants.Length() > 0) {
ASSERT(retain); // This shouldn't be the reason we keep a class.
retain = true;
}
@@ -1576,6 +1638,7 @@
void Precompiler::DropLibraries() {
const GrowableObjectArray& retained_libraries =
GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+ Library& root_lib = Library::Handle(Z, I->object_store()->root_library());
Library& lib = Library::Handle(Z);
for (intptr_t i = 0; i < libraries_.Length(); i++) {
@@ -1587,7 +1650,12 @@
it.GetNext();
entries++;
}
- bool retain = (entries > 0) || lib.is_dart_scheme();
+ // The root library might have no surviving members if it only exports main
+ // from another library. It will still be referenced from the object store,
+ // so retain it.
+ bool retain = (entries > 0) ||
+ lib.is_dart_scheme() ||
+ (lib.raw() == root_lib.raw());
if (retain) {
lib.set_index(retained_libraries.Length());
retained_libraries.Add(lib);
@@ -1618,7 +1686,6 @@
void VisitFunction(const Function& function) {
if (!function.HasCode()) {
- ASSERT(function.HasImplicitClosureFunction());
return;
}
code_ = function.CurrentCode();
@@ -1666,6 +1733,7 @@
void Precompiler::SwitchICCalls() {
+#if !defined(TARGET_ARCH_DBC)
// Now that all functions have been compiled, we can switch to an instance
// call sequence that loads the Code object and entry point directly from
// the ic data array instead indirectly through a Function in the ic data
@@ -1687,7 +1755,6 @@
void VisitFunction(const Function& function) {
if (!function.HasCode()) {
- ASSERT(function.HasImplicitClosureFunction());
return;
}
@@ -1740,6 +1807,7 @@
ASSERT(!I->compilation_allowed());
SwitchICCallsVisitor visitor(Z);
VisitFunctions(&visitor);
+#endif
}
@@ -1756,7 +1824,6 @@
void VisitFunction(const Function& function) {
if (!function.HasCode()) {
- ASSERT(function.HasImplicitClosureFunction());
return;
}
code_ = function.CurrentCode();
@@ -1807,7 +1874,6 @@
void VisitFunction(const Function& function) {
if (!function.HasCode()) {
- ASSERT(function.HasImplicitClosureFunction());
return;
}
code_ = function.CurrentCode();
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 5799819..5b6c7ac 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -309,6 +309,7 @@
void CheckForNewDynamicFunctions();
void TraceConstFunctions();
+ void TraceForRetainedFunctions();
void DropFunctions();
void DropFields();
void TraceTypesFromRetainedClasses();
@@ -362,6 +363,7 @@
SymbolSet sent_selectors_;
FunctionSet enqueued_functions_;
FieldSet fields_to_retain_;
+ FunctionSet functions_to_retain_;
ClassSet classes_to_retain_;
TypeArgumentsSet typeargs_to_retain_;
AbstractTypeSet types_to_retain_;
@@ -373,6 +375,7 @@
class FunctionsTraits {
public:
static const char* Name() { return "FunctionsTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
Zone* zone = Thread::Current()->zone();
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index e597260..394d795 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -290,6 +290,11 @@
ASSERT(return_address != NULL);
return false;
}
+#elif defined(TARGET_ARCH_DBC)
+bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) {
+ ASSERT(return_address != NULL);
+ return false;
+}
#else
#error ReturnAddressLocator implementation missing for this architecture.
#endif
@@ -323,6 +328,33 @@
}
+static void DumpStackFrame(intptr_t frame_index, uword pc) {
+ uintptr_t start = 0;
+ char* native_symbol_name =
+ NativeSymbolResolver::LookupSymbolName(pc, &start);
+ if (native_symbol_name == NULL) {
+ OS::Print("Frame[%" Pd "] = `unknown symbol` [0x%" Px "]\n",
+ frame_index, pc);
+ } else {
+ OS::Print("Frame[%" Pd "] = `%s` [0x%" Px "]\n",
+ frame_index, native_symbol_name, pc);
+ free(native_symbol_name);
+ }
+}
+
+
+static void DumpStackFrame(intptr_t frame_index,
+ uword pc,
+ const Code& code) {
+ if (code.IsNull()) {
+ DumpStackFrame(frame_index, pc);
+ } else {
+ OS::Print("Frame[%" Pd "] = Dart:`%s` [0x%" Px "]\n",
+ frame_index, code.ToCString(), pc);
+ }
+}
+
+
class ProfilerStackWalker : public ValueObject {
public:
ProfilerStackWalker(Isolate* isolate,
@@ -334,12 +366,31 @@
frame_index_(0),
total_frames_(0) {
ASSERT(isolate_ != NULL);
- ASSERT(sample_ != NULL);
- ASSERT(sample_buffer_ != NULL);
- ASSERT(sample_->head_sample());
+ if (sample_ == NULL) {
+ ASSERT(sample_buffer_ == NULL);
+ } else {
+ ASSERT(sample_buffer_ != NULL);
+ ASSERT(sample_->head_sample());
+ }
+ }
+
+ bool Append(uword pc, const Code& code) {
+ if (sample_ == NULL) {
+ DumpStackFrame(frame_index_, pc, code);
+ frame_index_++;
+ total_frames_++;
+ return true;
+ }
+ return Append(pc);
}
bool Append(uword pc) {
+ if (sample_ == NULL) {
+ DumpStackFrame(frame_index_, pc);
+ frame_index_++;
+ total_frames_++;
+ return true;
+ }
if (total_frames_ >= FLAG_max_profile_depth) {
sample_->set_truncated_trace(true);
return false;
@@ -387,11 +438,23 @@
sample_->set_exit_frame_sample(true);
StackFrame* frame = frame_iterator_.NextFrame();
- while (frame != NULL) {
- if (!Append(frame->pc())) {
- return;
+ if (sample_ == NULL) {
+ // Only when we are dumping the stack trace for debug purposes.
+ Code& code = Code::Handle();
+ while (frame != NULL) {
+ code ^= frame->LookupDartCode();
+ if (!Append(frame->pc(), code)) {
+ return;
+ }
+ frame = frame_iterator_.NextFrame();
}
- frame = frame_iterator_.NextFrame();
+ } else {
+ while (frame != NULL) {
+ if (!Append(frame->pc())) {
+ return;
+ }
+ frame = frame_iterator_.NextFrame();
+ }
}
}
@@ -576,7 +639,6 @@
void walk() {
const uword kMaxStep = VirtualMemory::PageSize();
-
Append(original_pc_);
uword* pc = reinterpret_cast<uword*>(original_pc_);
@@ -839,7 +901,7 @@
Sample* sample = sample_buffer->ReserveSample();
sample->Init(isolate, OS::GetCurrentMonotonicMicros(), tid);
uword vm_tag = thread->vm_tag();
-#if defined(USING_SIMULATOR)
+#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
// When running in the simulator, the runtime entry function address
// (stored as the vm tag) is the address of a redirect function.
// Attempt to find the real runtime entry function address and use that.
@@ -876,6 +938,78 @@
}
#endif
+
+void Profiler::DumpStackTrace(bool native_stack_trace) {
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ Isolate* isolate = thread->isolate();
+ if (!CheckIsolate(isolate)) {
+ return;
+ }
+
+ const bool exited_dart_code = thread->HasExitedDartCode();
+
+ OS::Print("Dumping %s stack trace for thread %" Px "\n",
+ native_stack_trace ? "native" : "dart-only",
+ OSThread::ThreadIdToIntPtr(os_thread->trace_id()));
+
+ uintptr_t sp = Thread::GetCurrentStackPointer();
+ uintptr_t fp = 0;
+ uintptr_t pc = GetProgramCounter();
+
+ COPY_FP_REGISTER(fp);
+
+ uword stack_lower = 0;
+ uword stack_upper = 0;
+
+ if (!InitialRegisterCheck(pc, fp, sp)) {
+ OS::Print(
+ "Stack dump aborted because InitialRegisterCheck.\n");
+ return;
+ }
+
+ if (!GetAndValidateIsolateStackBounds(thread,
+ fp,
+ sp,
+ &stack_lower,
+ &stack_upper)) {
+ OS::Print(
+ "Stack dump aborted because GetAndValidateIsolateStackBounds.\n");
+ return;
+ }
+
+ if (native_stack_trace) {
+ ProfilerNativeStackWalker native_stack_walker(isolate,
+ NULL,
+ NULL,
+ stack_lower,
+ stack_upper,
+ pc,
+ fp,
+ sp);
+ native_stack_walker.walk();
+ } else if (exited_dart_code) {
+ ProfilerDartExitStackWalker dart_exit_stack_walker(thread,
+ isolate,
+ NULL,
+ NULL);
+ dart_exit_stack_walker.walk();
+ } else {
+ ProfilerDartStackWalker dart_stack_walker(isolate,
+ NULL,
+ NULL,
+ stack_lower,
+ stack_upper,
+ pc,
+ fp,
+ sp);
+ }
+ OS::Print("-- End of DumpStackTrace");
+}
+
+
void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
ASSERT(thread != NULL);
OSThread* os_thread = thread->os_thread();
@@ -973,6 +1107,11 @@
void Profiler::SampleThread(Thread* thread,
const InterruptedThreadState& state) {
+#if defined(TARGET_ARCH_DBC)
+ // TODO(vegorov) implement simulator stack sampling.
+ return;
+#endif
+
ASSERT(thread != NULL);
OSThread* os_thread = thread->os_thread();
ASSERT(os_thread != NULL);
@@ -996,13 +1135,15 @@
uintptr_t sp = 0;
uintptr_t fp = state.fp;
uintptr_t pc = state.pc;
-#if defined(USING_SIMULATOR)
+#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
Simulator* simulator = NULL;
#endif
if (in_dart_code) {
// If we're in Dart code, use the Dart stack pointer.
-#if defined(USING_SIMULATOR)
+#if defined(TARGET_ARCH_DBC)
+ UNIMPLEMENTED();
+#elif defined(USING_SIMULATOR)
simulator = isolate->simulator();
sp = simulator->get_register(SPREG);
fp = simulator->get_register(FPREG);
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 096d429..32b4ec4 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -39,6 +39,8 @@
return sample_buffer_;
}
+ static void DumpStackTrace(bool native_stack_trace = true);
+
static void SampleAllocation(Thread* thread, intptr_t cid);
// SampleThread is called from inside the signal handler and hence it is very
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 6a5d626..2e67ee2 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -231,6 +231,8 @@
friend class object; \
friend class RawObject; \
friend class Heap; \
+ friend class Simulator; \
+ friend class SimulatorHelpers; \
DISALLOW_ALLOCATION(); \
DISALLOW_IMPLICIT_CONSTRUCTORS(Raw##object)
@@ -654,7 +656,8 @@
friend class RetainingPathVisitor; // GetClassId
friend class SkippedCodeFunctions; // StorePointer
friend class InstructionsReader; // tags_ check
- friend class InstructionsWriter;
+ friend class AssemblyInstructionsWriter;
+ friend class BlobInstructionsWriter;
friend class SnapshotReader;
friend class SnapshotWriter;
friend class String;
@@ -665,6 +668,8 @@
friend class StackFrame; // GetCodeObject assertion.
friend class CodeLookupTableBuilder; // profiler
friend class NativeEntry; // GetClassId
+ friend class Simulator;
+ friend class SimulatorHelpers;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
@@ -1025,14 +1030,12 @@
RawGrowableObjectArray* patch_classes_;
RawArray* imports_; // List of Namespaces imported without prefix.
RawArray* exports_; // List of re-exported Namespaces.
- RawArray* exports2_; // Copy of exports_, used by background
- // compiler to detect cycles without colliding
- // with mutator thread lookups.
RawInstance* load_error_; // Error iff load_state_ == kLoadError.
RawObject** to_snapshot() {
return reinterpret_cast<RawObject**>(&ptr()->load_error_);
}
RawArray* resolved_names_; // Cache of resolved names in library scope.
+ RawArray* exported_names_; // Cache of exported names by library.
RawArray* loaded_scripts_; // Array of scripts loaded in this library.
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->loaded_scripts_);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 0ca54d8..40c1e34 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1182,6 +1182,7 @@
} else {
library.InitResolvedNamesCache(kInitialNameCacheSize, reader);
}
+ library.StorePointer(&library.raw_ptr()->exported_names_, Array::null());
// Initialize cache of loaded scripts.
library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
}
@@ -1540,9 +1541,13 @@
break;
}
case ObjectPool::kNativeEntry: {
+#if !defined(TARGET_ARCH_DBC)
// Read nothing. Initialize with the lazy link entry.
uword new_entry = NativeEntry::LinkNativeCallEntry();
result->SetRawValueAt(i, static_cast<intptr_t>(new_entry));
+#else
+ UNREACHABLE(); // DBC does not support lazy native call linking.
+#endif
break;
}
default:
@@ -1592,14 +1597,16 @@
Entry& entry = ptr()->data()[i];
switch (entry_type) {
case ObjectPool::kTaggedObject: {
+#if !defined(TARGET_ARCH_DBC)
if (entry.raw_obj_ == StubCode::CallNativeCFunction_entry()->code()) {
// Natives can run while precompiling, becoming linked and switching
// their stub. Reset to the initial stub used for lazy-linking.
writer->WriteObjectImpl(
StubCode::CallBootstrapCFunction_entry()->code(), kAsReference);
- } else {
- writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
+ break;
}
+#endif
+ writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
break;
}
case ObjectPool::kImmediate: {
@@ -1608,6 +1615,9 @@
}
case ObjectPool::kNativeEntry: {
// Write nothing. Will initialize with the lazy link entry.
+#if defined(TARGET_ARCH_DBC)
+ UNREACHABLE(); // DBC does not support lazy native call linking.
+#endif
break;
}
default:
@@ -2293,7 +2303,7 @@
Instance::InstanceSize(),
HEAP_SPACE(kind));
if (RawObject::IsCanonical(tags)) {
- obj = obj.CheckAndCanonicalize(NULL);
+ obj = obj.CheckAndCanonicalize(reader->thread(), NULL);
}
}
reader->AddBackRef(object_id, &obj, kIsDeserialized);
@@ -2404,7 +2414,7 @@
// Set the canonical bit.
obj.SetCanonical();
} else {
- obj ^= obj.CheckAndCanonicalize(NULL);
+ obj ^= obj.CheckAndCanonicalize(reader->thread(), NULL);
ASSERT(!obj.IsNull());
ASSERT(obj.IsCanonical());
}
@@ -2831,7 +2841,7 @@
if (kind == Snapshot::kFull) {
array->SetCanonical();
} else {
- *array ^= array->CheckAndCanonicalize(NULL);
+ *array ^= array->CheckAndCanonicalize(reader->thread(), NULL);
}
}
}
@@ -3247,7 +3257,7 @@
// Set the canonical bit.
result.SetCanonical();
} else {
- result ^= result.CheckAndCanonicalize(NULL);
+ result ^= result.CheckAndCanonicalize(reader->thread(), NULL);
ASSERT(!result.IsNull());
ASSERT(result.IsCanonical());
}
diff --git a/runtime/vm/runtime_entry_dbc.cc b/runtime/vm/runtime_entry_dbc.cc
new file mode 100644
index 0000000..8e03f1a
--- /dev/null
+++ b/runtime/vm/runtime_entry_dbc.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h"
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/runtime_entry.h"
+
+#include "vm/assembler.h"
+#include "vm/simulator.h"
+#include "vm/stub_code.h"
+
+namespace dart {
+
+
+uword RuntimeEntry::GetEntryPoint() const {
+ return reinterpret_cast<uword>(function());
+}
+
+
+void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
+ UNIMPLEMENTED();
+}
+
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index ee6d8e9..47e77f4 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.3
+# Dart VM Service Protocol 3.4
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.3_ of the Dart VM Service Protocol. This
+This document describes of _version 3.4_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -512,7 +512,7 @@
FlagList getFlagList()
```
-The _getFlagList RPC returns a list of all command line flags in the
+The _getFlagList_ RPC returns a list of all command line flags in the
VM along with their current values.
See [FlagList](#flaglist).
diff --git a/runtime/vm/simulator.h b/runtime/vm/simulator.h
index 8a859e3..b73bd97 100644
--- a/runtime/vm/simulator.h
+++ b/runtime/vm/simulator.h
@@ -17,6 +17,8 @@
#include "vm/simulator_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/simulator_mips.h"
+#elif defined(TARGET_ARCH_DBC)
+#include "vm/simulator_dbc.h"
#else
#error Unknown architecture.
#endif // defined(TARGET_ARCH_...)
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 1fcb66b..f11bab7 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -44,7 +44,6 @@
// The runtime then does a Longjmp on that buffer to return to the simulator.
class SimulatorSetjmpBuffer {
public:
- int Setjmp() { return setjmp(buffer_); }
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
@@ -1546,7 +1545,7 @@
ASSERT(sizeof(NativeArguments) == 4*kWordSize);
arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0));
arguments.argc_tag_ = get_register(R1);
- arguments.argv_ = reinterpret_cast<RawObject*(*)[]>(get_register(R2));
+ arguments.argv_ = reinterpret_cast<RawObject**>(get_register(R2));
arguments.retval_ = reinterpret_cast<RawObject**>(get_register(R3));
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h
index af3cb09..ce18ac0 100644
--- a/runtime/vm/simulator_arm.h
+++ b/runtime/vm/simulator_arm.h
@@ -52,6 +52,10 @@
void set_register(Register reg, int32_t value);
int32_t get_register(Register reg) const;
+ int32_t get_sp() const {
+ return get_register(SPREG);
+ }
+
// Special case of set_register and get_register to access the raw PC value.
void set_pc(int32_t value);
int32_t get_pc() const;
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index cef6aa2..36f5f9c 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -43,7 +43,6 @@
// The runtime then does a Longjmp on that buffer to return to the simulator.
class SimulatorSetjmpBuffer {
public:
- int Setjmp() { return setjmp(buffer_); }
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index bf3572c..78c1812 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -65,6 +65,10 @@
void get_vregister(VRegister reg, simd_value_t* value) const;
void set_vregister(VRegister reg, const simd_value_t& value);
+ int64_t get_sp() const {
+ return get_register(SPREG);
+ }
+
int64_t get_pc() const;
int64_t get_last_pc() const;
void set_pc(int64_t pc);
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
new file mode 100644
index 0000000..7329114
--- /dev/null
+++ b/runtime/vm/simulator_dbc.cc
@@ -0,0 +1,1902 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include <setjmp.h> // NOLINT
+#include <stdlib.h>
+
+#include "vm/globals.h"
+#if defined(TARGET_ARCH_DBC)
+
+#if !defined(USING_SIMULATOR)
+#error "DBC is a simulated architecture"
+#endif
+
+#include "vm/simulator.h"
+
+#include "vm/assembler.h"
+#include "vm/compiler.h"
+#include "vm/constants_dbc.h"
+#include "vm/cpu.h"
+#include "vm/dart_entry.h"
+#include "vm/debugger.h"
+#include "vm/disassembler.h"
+#include "vm/lockers.h"
+#include "vm/native_arguments.h"
+#include "vm/native_entry.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/os_thread.h"
+#include "vm/stack_frame.h"
+
+namespace dart {
+
+DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX,
+ "Trace simulator execution after instruction count reached.");
+DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX,
+ "Instruction address or instruction count to stop simulator at.");
+
+// SimulatorSetjmpBuffer are linked together, and the last created one
+// is referenced by the Simulator. When an exception is thrown, the exception
+// runtime looks at where to jump and finds the corresponding
+// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
+// The runtime then does a Longjmp on that buffer to return to the simulator.
+class SimulatorSetjmpBuffer {
+ public:
+ void Longjmp() {
+ // "This" is now the last setjmp buffer.
+ simulator_->set_last_setjmp_buffer(this);
+ longjmp(buffer_, 1);
+ }
+
+ explicit SimulatorSetjmpBuffer(Simulator* sim) {
+ simulator_ = sim;
+ link_ = sim->last_setjmp_buffer();
+ sim->set_last_setjmp_buffer(this);
+ sp_ = sim->sp_;
+ fp_ = sim->fp_;
+ }
+
+ ~SimulatorSetjmpBuffer() {
+ ASSERT(simulator_->last_setjmp_buffer() == this);
+ simulator_->set_last_setjmp_buffer(link_);
+ }
+
+ SimulatorSetjmpBuffer* link() const { return link_; }
+
+ uword sp() const { return reinterpret_cast<uword>(sp_); }
+ uword fp() const { return reinterpret_cast<uword>(fp_); }
+
+ jmp_buf buffer_;
+
+ private:
+ RawObject** sp_;
+ RawObject** fp_;
+ Simulator* simulator_;
+ SimulatorSetjmpBuffer* link_;
+
+ friend class Simulator;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(SimulatorSetjmpBuffer);
+};
+
+
+DART_FORCE_INLINE static RawObject** SavedCallerFP(RawObject** FP) {
+ return reinterpret_cast<RawObject**>(FP[kSavedCallerFpSlotFromFp]);
+}
+
+
+DART_FORCE_INLINE static RawCode* FrameCode(RawObject** FP) {
+ return static_cast<RawCode*>(FP[kPcMarkerSlotFromFp]);
+}
+
+
+DART_FORCE_INLINE static void SetFrameCode(RawObject** FP, RawCode* code) {
+ FP[kPcMarkerSlotFromFp] = code;
+}
+
+
+DART_FORCE_INLINE static RawObject** FrameArguments(RawObject** FP,
+ intptr_t argc) {
+ return FP - (kDartFrameFixedSize + argc);
+}
+
+
+class SimulatorHelpers {
+ public:
+ DART_FORCE_INLINE static RawSmi* GetClassIdAsSmi(RawObject* obj) {
+ return Smi::New(obj->IsHeapObject() ? obj->GetClassId()
+ : static_cast<intptr_t>(kSmiCid));
+ }
+
+ DART_FORCE_INLINE static intptr_t GetClassId(RawObject* obj) {
+ return obj->IsHeapObject() ? obj->GetClassId()
+ : static_cast<intptr_t>(kSmiCid);
+ }
+
+ DART_FORCE_INLINE static void IncrementUsageCounter(RawICData* icdata) {
+ reinterpret_cast<RawFunction*>(icdata->ptr()->owner_)
+ ->ptr()
+ ->usage_counter_++;
+ }
+
+ DART_FORCE_INLINE static bool IsStrictEqualWithNumberCheck(RawObject* lhs,
+ RawObject* rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+
+ if (lhs->IsHeapObject() && rhs->IsHeapObject()) {
+ const intptr_t lhs_cid = lhs->GetClassId();
+ const intptr_t rhs_cid = rhs->GetClassId();
+ if (lhs_cid == rhs_cid) {
+ switch (lhs_cid) {
+ case kDoubleCid:
+ return (bit_cast<uint64_t, double>(
+ static_cast<RawDouble*>(lhs)->ptr()->value_) ==
+ bit_cast<uint64_t, double>(
+ static_cast<RawDouble*>(rhs)->ptr()->value_));
+
+ case kMintCid:
+ return (static_cast<RawMint*>(lhs)->ptr()->value_ ==
+ static_cast<RawMint*>(rhs)->ptr()->value_);
+
+ case kBigintCid:
+ return (DLRT_BigintCompare(static_cast<RawBigint*>(lhs),
+ static_cast<RawBigint*>(rhs)) == 0);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ template <typename T>
+ DART_FORCE_INLINE static T* Untag(T* tagged) {
+ return tagged->ptr();
+ }
+
+ DART_FORCE_INLINE static bool CheckIndex(RawSmi* index, RawSmi* length) {
+ return !index->IsHeapObject() &&
+ (reinterpret_cast<intptr_t>(index) >= 0) &&
+ (reinterpret_cast<intptr_t>(index) <
+ reinterpret_cast<intptr_t>(length));
+ }
+
+ static bool ObjectArraySetIndexed(Thread* thread,
+ RawObject** FP,
+ RawObject** result) {
+ if (thread->isolate()->type_checks()) {
+ return false;
+ }
+
+ RawObject** args = FrameArguments(FP, 3);
+ RawSmi* index = static_cast<RawSmi*>(args[1]);
+ RawArray* array = static_cast<RawArray*>(args[0]);
+ if (CheckIndex(index, array->ptr()->length_)) {
+ array->StorePointer(array->ptr()->data() + Smi::Value(index), args[2]);
+ return true;
+ }
+ return false;
+ }
+
+ static bool ObjectArrayGetIndexed(Thread* thread,
+ RawObject** FP,
+ RawObject** result) {
+ RawObject** args = FrameArguments(FP, 2);
+ RawSmi* index = static_cast<RawSmi*>(args[1]);
+ RawArray* array = static_cast<RawArray*>(args[0]);
+ if (CheckIndex(index, array->ptr()->length_)) {
+ *result = array->ptr()->data()[Smi::Value(index)];
+ return true;
+ }
+ return false;
+ }
+
+ static bool GrowableArraySetIndexed(Thread* thread,
+ RawObject** FP,
+ RawObject** result) {
+ if (thread->isolate()->type_checks()) {
+ return false;
+ }
+
+ RawObject** args = FrameArguments(FP, 3);
+ RawSmi* index = static_cast<RawSmi*>(args[1]);
+ RawGrowableObjectArray* array =
+ static_cast<RawGrowableObjectArray*>(args[0]);
+ if (CheckIndex(index, array->ptr()->length_)) {
+ RawArray* data = array->ptr()->data_;
+ data->StorePointer(data->ptr()->data() + Smi::Value(index), args[2]);
+ return true;
+ }
+ return false;
+ }
+
+ static bool GrowableArrayGetIndexed(Thread* thread,
+ RawObject** FP,
+ RawObject** result) {
+ RawObject** args = FrameArguments(FP, 2);
+ RawSmi* index = static_cast<RawSmi*>(args[1]);
+ RawGrowableObjectArray* array =
+ static_cast<RawGrowableObjectArray*>(args[0]);
+ if (CheckIndex(index, array->ptr()->length_)) {
+ *result = array->ptr()->data_->ptr()->data()[Smi::Value(index)];
+ return true;
+ }
+ return false;
+ }
+};
+
+
+DART_FORCE_INLINE static uint32_t* SavedCallerPC(RawObject** FP) {
+ return reinterpret_cast<uint32_t*>(FP[kSavedCallerPcSlotFromFp]);
+}
+
+
+DART_FORCE_INLINE static RawFunction* FrameFunction(RawObject** FP) {
+ RawFunction* function = static_cast<RawFunction*>(FP[kFunctionSlotFromFp]);
+ ASSERT(SimulatorHelpers::GetClassId(function) == kFunctionCid);
+ return function;
+}
+
+
+IntrinsicHandler Simulator::intrinsics_[Simulator::kIntrinsicCount];
+
+
+// Synchronization primitives support.
+void Simulator::InitOnce() {
+ for (intptr_t i = 0; i < kIntrinsicCount; i++) {
+ intrinsics_[i] = 0;
+ }
+
+ intrinsics_[kObjectArraySetIndexedIntrinsic] =
+ SimulatorHelpers::ObjectArraySetIndexed;
+ intrinsics_[kObjectArrayGetIndexedIntrinsic] =
+ SimulatorHelpers::ObjectArrayGetIndexed;
+ intrinsics_[kGrowableArraySetIndexedIntrinsic] =
+ SimulatorHelpers::GrowableArraySetIndexed;
+ intrinsics_[kGrowableArrayGetIndexedIntrinsic] =
+ SimulatorHelpers::GrowableArrayGetIndexed;
+}
+
+
+Simulator::Simulator()
+ : stack_(NULL),
+ fp_(NULL),
+ sp_(NULL) {
+ // Setup simulator support first. Some of this information is needed to
+ // setup the architecture state.
+ // We allocate the stack here, the size is computed as the sum of
+ // the size specified by the user and the buffer space needed for
+ // handling stack overflow exceptions. To be safe in potential
+ // stack underflows we also add some underflow buffer space.
+ stack_ = new uintptr_t[(OSThread::GetSpecifiedStackSize() +
+ OSThread::kStackSizeBuffer +
+ kSimulatorStackUnderflowSize) /
+ sizeof(uintptr_t)];
+ last_setjmp_buffer_ = NULL;
+ top_exit_frame_info_ = 0;
+}
+
+
+Simulator::~Simulator() {
+ delete[] stack_;
+ Isolate* isolate = Isolate::Current();
+ if (isolate != NULL) {
+ isolate->set_simulator(NULL);
+ }
+}
+
+
+// Get the active Simulator for the current isolate.
+Simulator* Simulator::Current() {
+ Simulator* simulator = Isolate::Current()->simulator();
+ if (simulator == NULL) {
+ simulator = new Simulator();
+ Isolate::Current()->set_simulator(simulator);
+ }
+ return simulator;
+}
+
+
+// Returns the top of the stack area to enable checking for stack pointer
+// validity.
+uword Simulator::StackTop() const {
+ // To be safe in potential stack underflows we leave some buffer above and
+ // set the stack top.
+ return StackBase() +
+ (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
+}
+
+
+// Calls into the Dart runtime are based on this interface.
+typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
+
+// Calls to leaf Dart runtime functions are based on this interface.
+typedef intptr_t (*SimulatorLeafRuntimeCall)(intptr_t r0,
+ intptr_t r1,
+ intptr_t r2,
+ intptr_t r3);
+
+// Calls to leaf float Dart runtime functions are based on this interface.
+typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
+
+// Calls to native Dart functions are based on this interface.
+typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments);
+typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target);
+
+
+void Simulator::Exit(Thread* thread,
+ RawObject** base,
+ RawObject** frame,
+ uint32_t* pc) {
+ frame[0] = Function::null();
+ frame[1] = Code::null();
+ frame[2] = reinterpret_cast<RawObject*>(pc);
+ frame[3] = reinterpret_cast<RawObject*>(base);
+ fp_ = sp_ = frame + kDartFrameFixedSize;
+ thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_));
+}
+
+// TODO(vegorov): Investigate advantages of using
+// __builtin_s{add,sub,mul}_overflow() intrinsics here and below.
+// Note that they may clobber the output location even when there is overflow:
+// https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
+DART_FORCE_INLINE static bool SignedAddWithOverflow(intptr_t lhs,
+ intptr_t rhs,
+ intptr_t* out) {
+ intptr_t res = 1;
+#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+ asm volatile(
+ "add %2, %1\n"
+ "jo 1f;\n"
+ "xor %0, %0\n"
+ "mov %1, 0(%3)\n"
+ "1: "
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
+ asm volatile(
+ "adds %1, %1, %2;\n"
+ "bvs 1f;\n"
+ "mov %0, #0;\n"
+ "str %1, [%3, #0]\n"
+ "1:"
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#else
+#error "Unsupported platform"
+#endif
+ return (res != 0);
+}
+
+
+DART_FORCE_INLINE static bool SignedSubWithOverflow(intptr_t lhs,
+ intptr_t rhs,
+ intptr_t* out) {
+ intptr_t res = 1;
+#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+ asm volatile(
+ "sub %2, %1\n"
+ "jo 1f;\n"
+ "xor %0, %0\n"
+ "mov %1, 0(%3)\n"
+ "1: "
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
+ asm volatile(
+ "subs %1, %1, %2;\n"
+ "bvs 1f;\n"
+ "mov %0, #0;\n"
+ "str %1, [%3, #0]\n"
+ "1:"
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#else
+#error "Unsupported platform"
+#endif
+ return (res != 0);
+}
+
+
+DART_FORCE_INLINE static bool SignedMulWithOverflow(intptr_t lhs,
+ intptr_t rhs,
+ intptr_t* out) {
+ intptr_t res = 1;
+#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+ asm volatile(
+ "imul %2, %1\n"
+ "jo 1f;\n"
+ "xor %0, %0\n"
+ "mov %1, 0(%3)\n"
+ "1: "
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#elif defined(HOST_ARCH_ARM)
+ asm volatile(
+ "smull %1, ip, %1, %2;\n"
+ "cmp ip, %1, ASR #31;\n"
+ "bne 1f;\n"
+ "mov %0, $0;\n"
+ "str %1, [%3, #0]\n"
+ "1:"
+ : "+r"(res), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc", "r12");
+#elif defined(HOST_ARCH_ARM64)
+ int64_t prod_lo;
+ asm volatile(
+ "mul %1, %2, %3\n"
+ "smulh %2, %2, %3\n"
+ "cmp %2, %1, ASR #63;\n"
+ "bne 1f;\n"
+ "mov %0, #0;\n"
+ "str %1, [%4, #0]\n"
+ "1:"
+ : "+r"(res), "=r"(prod_lo), "+r"(lhs)
+ : "r"(rhs), "r"(out)
+ : "cc");
+#else
+#error "Unsupported platform"
+#endif
+ return (res != 0);
+}
+
+
+#define LIKELY(cond) __builtin_expect((cond), 1)
+
+
+DART_FORCE_INLINE static bool AreBothSmis(intptr_t a, intptr_t b) {
+ return ((a | b) & kHeapObjectTag) == 0;
+}
+
+
+#define SMI_MUL(lhs, rhs, pres) SignedMulWithOverflow((lhs), (rhs) >> 1, pres)
+#define SMI_COND(cond, lhs, rhs, pres) \
+ ((*(pres) = ((lhs cond rhs) ? true_value : false_value)), false)
+#define SMI_EQ(lhs, rhs, pres) SMI_COND(==, lhs, rhs, pres)
+#define SMI_LT(lhs, rhs, pres) SMI_COND(<, lhs, rhs, pres)
+#define SMI_GT(lhs, rhs, pres) SMI_COND(>, lhs, rhs, pres)
+#define SMI_BITOR(lhs, rhs, pres) ((*(pres) = (lhs | rhs)), false)
+#define SMI_BITAND(lhs, rhs, pres) ((*(pres) = ((lhs) & (rhs))), false)
+
+
+void Simulator::CallRuntime(Thread* thread,
+ RawObject** base,
+ RawObject** exit_frame,
+ uint32_t* pc,
+ intptr_t argc_tag,
+ RawObject** args,
+ RawObject** result,
+ uword target) {
+ Exit(thread, base, exit_frame, pc);
+ NativeArguments native_args(thread, argc_tag, args, result);
+ reinterpret_cast<RuntimeFunction>(target)(native_args);
+}
+
+
+DART_FORCE_INLINE void Simulator::Invoke(Thread* thread,
+ RawObject** call_base,
+ RawObject** call_top,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** FP,
+ RawObject*** SP) {
+ RawObject** callee_fp = call_top + kDartFrameFixedSize;
+
+ RawFunction* function = FrameFunction(callee_fp);
+ RawCode* code = function->ptr()->code_;
+ callee_fp[kPcMarkerSlotFromFp] = code;
+ callee_fp[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc);
+ callee_fp[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP);
+ *pp = code->ptr()->object_pool_->ptr();
+ *pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
+ *FP = callee_fp;
+ *SP = *FP - 1;
+}
+
+
+void Simulator::InlineCacheMiss(int checked_args,
+ Thread* thread,
+ RawICData* icdata,
+ RawObject** args,
+ RawObject** top,
+ uint32_t* pc,
+ RawObject** FP,
+ RawObject** SP) {
+ RawObject** result = top;
+ RawObject** miss_handler_args = top + 1;
+ for (intptr_t i = 0; i < checked_args; i++) {
+ miss_handler_args[i] = args[i];
+ }
+ miss_handler_args[checked_args] = icdata;
+ RuntimeFunction handler = NULL;
+ switch (checked_args) {
+ case 1:
+ handler = DRT_InlineCacheMissHandlerOneArg;
+ break;
+ case 2:
+ handler = DRT_InlineCacheMissHandlerTwoArgs;
+ break;
+ case 3:
+ handler = DRT_InlineCacheMissHandlerThreeArgs;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ // Handler arguments: arguments to check and an ICData object.
+ const intptr_t miss_handler_argc = checked_args + 1;
+ RawObject** exit_frame = miss_handler_args + miss_handler_argc;
+ CallRuntime(thread,
+ FP,
+ exit_frame,
+ pc,
+ miss_handler_argc,
+ miss_handler_args,
+ result,
+ reinterpret_cast<uword>(handler));
+}
+
+
+DART_FORCE_INLINE void Simulator::InstanceCall1(Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** top,
+ RawArray** argdesc,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** FP,
+ RawObject*** SP) {
+ ASSERT(icdata->GetClassId() == kICDataCid);
+ SimulatorHelpers::IncrementUsageCounter(icdata);
+
+ const intptr_t kCheckedArgs = 1;
+ RawObject** args = call_base;
+ RawArray* cache = icdata->ptr()->ic_data_->ptr();
+
+ RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]);
+
+ bool found = false;
+ const intptr_t length = Smi::Value(cache->length_);
+ for (intptr_t i = 0;
+ i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) {
+ if (cache->data()[i + 0] == receiver_cid) {
+ top[0] = cache->data()[i + kCheckedArgs];
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ InlineCacheMiss(
+ kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP);
+ }
+
+ *argdesc = icdata->ptr()->args_descriptor_;
+ Invoke(thread, call_base, top, pp, pc, FP, SP);
+}
+
+
+DART_FORCE_INLINE void Simulator::InstanceCall2(Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** top,
+ RawArray** argdesc,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** FP,
+ RawObject*** SP) {
+ ASSERT(icdata->GetClassId() == kICDataCid);
+ SimulatorHelpers::IncrementUsageCounter(icdata);
+
+ const intptr_t kCheckedArgs = 2;
+ RawObject** args = call_base;
+ RawArray* cache = icdata->ptr()->ic_data_->ptr();
+
+ RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]);
+ RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]);
+
+ bool found = false;
+ const intptr_t length = Smi::Value(cache->length_);
+ for (intptr_t i = 0;
+ i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) {
+ if ((cache->data()[i + 0] == receiver_cid) &&
+ (cache->data()[i + 1] == arg0_cid)) {
+ top[0] = cache->data()[i + kCheckedArgs];
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ InlineCacheMiss(
+ kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP);
+ }
+
+ *argdesc = icdata->ptr()->args_descriptor_;
+ Invoke(thread, call_base, top, pp, pc, FP, SP);
+}
+
+
+DART_FORCE_INLINE void Simulator::InstanceCall3(Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** top,
+ RawArray** argdesc,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** FP,
+ RawObject*** SP) {
+ ASSERT(icdata->GetClassId() == kICDataCid);
+ SimulatorHelpers::IncrementUsageCounter(icdata);
+
+ const intptr_t kCheckedArgs = 3;
+ RawObject** args = call_base;
+ RawArray* cache = icdata->ptr()->ic_data_->ptr();
+
+ RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]);
+ RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]);
+ RawSmi* arg1_cid = SimulatorHelpers::GetClassIdAsSmi(args[2]);
+
+ bool found = false;
+ const intptr_t length = Smi::Value(cache->length_);
+ for (intptr_t i = 0;
+ i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) {
+ if ((cache->data()[i + 0] == receiver_cid) &&
+ (cache->data()[i + 1] == arg0_cid) &&
+ (cache->data()[i + 2] == arg1_cid)) {
+ top[0] = cache->data()[i + kCheckedArgs];
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ InlineCacheMiss(
+ kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP);
+ }
+
+ *argdesc = icdata->ptr()->args_descriptor_;
+ Invoke(thread, call_base, top, pp, pc, FP, SP);
+}
+
+
+// Note: functions below are marked DART_NOINLINE to recover performance on
+// ARM where inlining these functions into the interpreter loop seemed to cause
+// some code quality issues.
+static DART_NOINLINE bool InvokeRuntime(
+ Thread* thread,
+ Simulator* sim,
+ RuntimeFunction drt,
+ const NativeArguments& args) {
+ SimulatorSetjmpBuffer buffer(sim);
+ if (!setjmp(buffer.buffer_)) {
+ thread->set_vm_tag(reinterpret_cast<uword>(drt));
+ drt(args);
+ thread->set_vm_tag(VMTag::kDartTagId);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static DART_NOINLINE bool InvokeNative(
+ Thread* thread,
+ Simulator* sim,
+ SimulatorBootstrapNativeCall f,
+ NativeArguments* args) {
+ SimulatorSetjmpBuffer buffer(sim);
+ if (!setjmp(buffer.buffer_)) {
+ thread->set_vm_tag(reinterpret_cast<uword>(f));
+ f(args);
+ thread->set_vm_tag(VMTag::kDartTagId);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static DART_NOINLINE bool InvokeNativeWrapper(
+ Thread* thread,
+ Simulator* sim,
+ Dart_NativeFunction f,
+ NativeArguments* args) {
+ SimulatorSetjmpBuffer buffer(sim);
+ if (!setjmp(buffer.buffer_)) {
+ thread->set_vm_tag(reinterpret_cast<uword>(f));
+ NativeEntry::NativeCallWrapper(reinterpret_cast<Dart_NativeArguments>(args),
+ f);
+ thread->set_vm_tag(VMTag::kDartTagId);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Note: all macro helpers are intended to be used only inside Simulator::Call.
+
+// Decode opcode and A part of the given value and dispatch to the
+// corresponding bytecode handler.
+#define DISPATCH_OP(val) \
+ do { \
+ op = (val); \
+ rA = ((op >> 8) & 0xFF); \
+ goto* dispatch[op & 0xFF]; \
+ } while (0)
+
+// Fetch next operation from PC, increment program counter and dispatch.
+#define DISPATCH() DISPATCH_OP(*pc++)
+
+// Define entry point that handles bytecode Name with the given operand format.
+#define BYTECODE(Name, Operands) \
+ BYTECODE_HEADER(Name, DECLARE_##Operands, DECODE_##Operands)
+
+#define BYTECODE_HEADER(Name, Declare, Decode) \
+ Declare; \
+ bc##Name : Decode \
+
+// Helpers to decode common instruction formats. Used in conjunction with
+// BYTECODE() macro.
+#define DECLARE_A_B_C uint16_t rB, rC; USE(rB); USE(rC)
+#define DECODE_A_B_C \
+ rB = ((op >> Bytecode::kBShift) & Bytecode::kBMask); \
+ rC = ((op >> Bytecode::kCShift) & Bytecode::kCMask);
+
+#define DECLARE_0
+#define DECODE_0
+
+#define DECLARE_A
+#define DECODE_A
+
+#define DECLARE___D uint32_t rD; USE(rD)
+#define DECODE___D rD = (op >> Bytecode::kDShift);
+
+#define DECLARE_A_D DECLARE___D
+#define DECODE_A_D DECODE___D
+
+#define DECLARE_A_X int32_t rD; USE(rD)
+#define DECODE_A_X rD = (static_cast<int32_t>(op) >> Bytecode::kDShift);
+
+// Declare bytecode handler for a smi operation (e.g. AddTOS) with the
+// given result type and the given behavior specified as a function
+// that takes left and right operands and result slot and returns
+// true if fast-path succeeds.
+#define SMI_FASTPATH_TOS(ResultT, Func) \
+ { \
+ const intptr_t lhs = reinterpret_cast<intptr_t>(SP[-1]); \
+ const intptr_t rhs = reinterpret_cast<intptr_t>(SP[-0]); \
+ ResultT* slot = reinterpret_cast<ResultT*>(SP - 1); \
+ if (LIKELY(AreBothSmis(lhs, rhs) && !Func(lhs, rhs, slot))) { \
+ /* Fast path succeeded. Skip the generic call that follows. */ \
+ pc++; \
+ /* We dropped 2 arguments and push result */ \
+ SP--; \
+ } \
+ }
+
+// Exception handling helper. Gets handler FP and PC from the Simulator where
+// they were stored by Simulator::Longjmp and proceeds to execute the handler.
+// Corner case: handler PC can be a fake marker that marks entry frame, which
+// means exception was not handled in the Dart code. In this case we return
+// caught exception from Simulator::Call.
+#define HANDLE_EXCEPTION \
+ do { \
+ FP = reinterpret_cast<RawObject**>(fp_); \
+ pc = reinterpret_cast<uint32_t*>(pc_); \
+ if ((reinterpret_cast<uword>(pc) & 2) != 0) { /* Entry frame? */ \
+ fp_ = sp_ = reinterpret_cast<RawObject**>(fp_[0]); \
+ thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_)); \
+ thread->set_top_resource(top_resource); \
+ thread->set_vm_tag(vm_tag); \
+ return special_[kExceptionSpecialIndex]; \
+ } \
+ pp = FrameCode(FP)->ptr()->object_pool_->ptr(); \
+ goto DispatchAfterException; \
+ } while (0) \
+
+// Runtime call helpers: handle invocation and potential exception after return.
+#define INVOKE_RUNTIME(Func, Args) \
+ if (!InvokeRuntime(thread, this, Func, Args)) { \
+ HANDLE_EXCEPTION; \
+ } \
+
+#define INVOKE_NATIVE(Func, Args) \
+ if (!InvokeNative(thread, this, Func, &Args)) { \
+ HANDLE_EXCEPTION; \
+ } \
+
+#define INVOKE_NATIVE_WRAPPER(Func, Args) \
+ if (!InvokeNativeWrapper(thread, this, Func, &Args)) { \
+ HANDLE_EXCEPTION; \
+ } \
+
+#define LOAD_CONSTANT(index) (pp->data()[(index)].raw_obj_)
+
+RawObject* Simulator::Call(const Code& code,
+ const Array& arguments_descriptor,
+ const Array& arguments,
+ Thread* thread) {
+ // Dispatch used to interpret bytecode. Contains addresses of
+ // labels of bytecode handlers. Handlers themselves are defined below.
+ static const void* dispatch[] = {
+#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
+ BYTECODES_LIST(TARGET)
+#undef TARGET
+ };
+
+ // Interpreter state (see constants_dbc.h for high-level overview).
+ uint32_t* pc; // Program Counter: points to the next op to execute.
+ RawObjectPool* pp; // Pool Pointer.
+ RawObject** FP; // Frame Pointer.
+ RawObject** SP; // Stack Pointer.
+
+ RawArray* argdesc; // Arguments Descriptor: used to pass information between
+ // call instruction and the function entry.
+
+ uint32_t op; // Currently executing op.
+ uint16_t rA; // A component of the currently executing op.
+
+ if (sp_ == NULL) {
+ fp_ = sp_ = reinterpret_cast<RawObject**>(stack_);
+ }
+
+ // Save current VM tag and mark thread as executing Dart code.
+ const uword vm_tag = thread->vm_tag();
+ thread->set_vm_tag(VMTag::kDartTagId);
+
+ // Save current top stack resource and reset the list.
+ StackResource* top_resource = thread->top_resource();
+ thread->set_top_resource(NULL);
+
+ // Setup entry frame:
+ //
+ // ^
+ // | previous Dart frames
+ // ~~~~~~~~~~~~~~~ |
+ // | ........... | -+
+ // fp_ > | | saved top_exit_frame_info
+ // | arg 0 | -+
+ // ~~~~~~~~~~~~~~~ |
+ // > incoming arguments
+ // ~~~~~~~~~~~~~~~ |
+ // | arg 1 | -+
+ // | function | -+
+ // | code | |
+ // | callee PC | ---> special fake PC marking an entry frame
+ // SP > | fp_ | |
+ // FP > | ........... | > normal Dart frame (see stack_frame_dbc.h)
+ // |
+ // v
+ //
+ FP = fp_ + 1 + arguments.Length() + kDartFrameFixedSize;
+ SP = FP - 1;
+
+ // Save outer top_exit_frame_info.
+ fp_[0] = reinterpret_cast<RawObject*>(thread->top_exit_frame_info());
+
+ // Copy arguments and setup the Dart frame.
+ const intptr_t argc = arguments.Length();
+ for (intptr_t i = 0; i < argc; i++) {
+ fp_[1 + i] = arguments.At(i);
+ }
+
+ FP[kFunctionSlotFromFp] = code.function();
+ FP[kPcMarkerSlotFromFp] = code.raw();
+ FP[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>((argc << 2) | 2);
+ FP[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(fp_);
+
+ // Load argument descriptor.
+ argdesc = arguments_descriptor.raw();
+
+ // Ready to start executing bytecode. Load entry point and corresponding
+ // object pool.
+ pc = reinterpret_cast<uint32_t*>(code.raw()->ptr()->entry_point_);
+ pp = code.object_pool()->ptr();
+
+ // Cache some frequently used values in the frame.
+ RawBool* true_value = Bool::True().raw();
+ RawBool* false_value = Bool::False().raw();
+ RawObject* null_value = Object::null();
+ RawObject* empty_context = thread->isolate()->object_store()->empty_context();
+
+#if defined(DEBUG)
+ Function& function_h = Function::Handle();
+#endif
+
+ // Enter the dispatch loop.
+ DISPATCH();
+
+ // Bytecode handlers (see constants_dbc.h for bytecode descriptions).
+ {
+ BYTECODE(Entry, A_B_C);
+ const uint8_t num_fixed_params = rA;
+ const uint16_t num_locals = rB;
+ const uint16_t context_reg = rC;
+
+ // Decode arguments descriptor.
+ const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
+ reinterpret_cast<uword>(argdesc->ptr()) +
+ Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
+
+ // Check that we got the right number of positional parameters.
+ if (pos_count != num_fixed_params) {
+ // Mismatch can only occur if current function is a closure.
+ goto ClosureNoSuchMethod;
+ }
+
+ // Initialize locals with null and set current context variable to
+ // empty context.
+ {
+ RawObject** L = FP;
+ for (intptr_t i = 0; i < num_locals; i++) {
+ L[i] = null_value;
+ }
+ L[context_reg] = empty_context;
+ SP = FP + num_locals - 1;
+ }
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(EntryOpt, A_B_C);
+ const uint16_t num_fixed_params = rA;
+ const uint16_t num_opt_pos_params = rB;
+ const uint16_t num_opt_named_params = rC;
+ const intptr_t min_num_pos_args = num_fixed_params;
+ const intptr_t max_num_pos_args = num_fixed_params + num_opt_pos_params;
+
+ // Decode arguments descriptor.
+ const intptr_t arg_count = Smi::Value(*reinterpret_cast<RawSmi**>(
+ reinterpret_cast<uword>(argdesc->ptr()) +
+ Array::element_offset(ArgumentsDescriptor::kCountIndex)));
+ const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
+ reinterpret_cast<uword>(argdesc->ptr()) +
+ Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
+ const intptr_t named_count = (arg_count - pos_count);
+
+ // Check that got the right number of positional parameters.
+ if ((min_num_pos_args > pos_count) || (pos_count > max_num_pos_args)) {
+ goto ClosureNoSuchMethod;
+ }
+
+ // Copy all passed position arguments.
+ RawObject** first_arg = FrameArguments(FP, arg_count);
+ memmove(FP, first_arg, pos_count * kWordSize);
+
+ if (num_opt_named_params != 0) {
+ // This is a function with named parameters.
+ // Walk the list of named parameters and their
+ // default values encoded as pairs of LoadConstant instructions that
+ // follows the entry point and find matching values via arguments
+ // descriptor.
+ RawObject** argdesc_data = argdesc->ptr()->data();
+
+ intptr_t i = named_count - 1; // argument position
+ intptr_t j = num_opt_named_params - 1; // parameter position
+ while ((j >= 0) && (i >= 0)) {
+ // Fetch formal parameter information: name, default value, target slot.
+ const uint32_t load_name = pc[2 * j];
+ const uint32_t load_value = pc[2 * j + 1];
+ ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant);
+ ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
+ const uint8_t reg = Bytecode::DecodeA(load_name);
+ ASSERT(reg == Bytecode::DecodeA(load_value));
+
+ RawString* name = static_cast<RawString*>(
+ LOAD_CONSTANT(Bytecode::DecodeD(load_name)));
+ if (name == argdesc_data[ArgumentsDescriptor::name_index(i)]) {
+ // Parameter was passed. Fetch passed value.
+ const intptr_t arg_index = Smi::Value(static_cast<RawSmi*>(
+ argdesc_data[ArgumentsDescriptor::position_index(i)]));
+ FP[reg] = first_arg[arg_index];
+ i--; // Consume passed argument.
+ } else {
+ // Parameter was not passed. Fetch default value.
+ FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
+ }
+ j--; // Next formal parameter.
+ }
+
+ // If we have unprocessed formal parameters then initialize them all
+ // using default values.
+ while (j >= 0) {
+ const uint32_t load_name = pc[2 * j];
+ const uint32_t load_value = pc[2 * j + 1];
+ ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant);
+ ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
+ const uint8_t reg = Bytecode::DecodeA(load_name);
+ ASSERT(reg == Bytecode::DecodeA(load_value));
+
+ FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
+ j--;
+ }
+
+ // If we have unprocessed passed arguments that means we have mismatch
+ // between formal parameters and concrete arguments. This can only
+ // occur if the current function is a closure.
+ if (i != -1) {
+ goto ClosureNoSuchMethod;
+ }
+
+ // Skip LoadConstant-s encoding information about named parameters.
+ pc += num_opt_named_params * 2;
+
+ // SP points past copied arguments.
+ SP = FP + num_fixed_params + num_opt_named_params - 1;
+ } else {
+ ASSERT(num_opt_pos_params != 0);
+ if (named_count != 0) {
+ // Function can't have both named and optional positional parameters.
+ // This kind of mismatch can only occur if the current function
+ // is a closure.
+ goto ClosureNoSuchMethod;
+ }
+
+ // Process the list of default values encoded as a sequence of
+ // LoadConstant instructions after EntryOpt bytecode.
+ // Execute only those that correspond to parameters the were not passed.
+ for (intptr_t i = pos_count - num_fixed_params;
+ i < num_opt_pos_params;
+ i++) {
+ const uint32_t load_value = pc[i];
+ ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
+#if defined(DEBUG)
+ const uint8_t reg = Bytecode::DecodeA(load_value);
+ ASSERT((num_fixed_params + i) == reg);
+#endif
+ FP[num_fixed_params + i] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
+ }
+
+ // Skip LoadConstant-s encoding default values for optional positional
+ // parameters.
+ pc += num_opt_pos_params;
+
+ // SP points past the last copied parameter.
+ SP = FP + max_num_pos_args - 1;
+ }
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Frame, A_D);
+ // Initialize locals with null and increment SP.
+ const uint16_t num_locals = rD;
+ for (intptr_t i = 1; i <= num_locals; i++) {
+ SP[i] = null_value;
+ }
+ SP += num_locals;
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(SetFrame, A);
+ SP = FP + rA - 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Compile, 0);
+ FP[0] = FrameFunction(FP);
+ FP[1] = 0;
+ Exit(thread, FP, FP + 2, pc);
+ NativeArguments args(thread, 1, FP, FP + 1);
+ INVOKE_RUNTIME(DRT_CompileFunction, args);
+ {
+ // Function should be compiled now, dispatch to its entry point.
+ RawCode* code = FrameFunction(FP)->ptr()->code_;
+ SetFrameCode(FP, code);
+ pp = code->ptr()->object_pool_->ptr();
+ pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(CheckStack, A);
+ {
+ if (reinterpret_cast<uword>(SP) >= thread->stack_limit()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_StackOverflow, args);
+ }
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DebugStep, A);
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DebugBreak, A);
+ {
+ const uint32_t original_bc =
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(
+ thread->isolate()->debugger()->GetPatchedStubAddress(
+ reinterpret_cast<uword>(pc))));
+
+ SP[1] = null_value;
+ Exit(thread, FP, SP + 2, pc);
+ NativeArguments args(thread, 0, NULL, SP + 1);
+ INVOKE_RUNTIME(DRT_BreakpointRuntimeHandler, args)
+ DISPATCH_OP(original_bc);
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(InstantiateType, A_D);
+ RawObject* type = LOAD_CONSTANT(rD);
+ SP[1] = type;
+ SP[2] = SP[0];
+ SP[0] = null_value;
+ Exit(thread, FP, SP + 3, pc);
+ {
+ NativeArguments args(thread, 2, SP + 1, SP);
+ INVOKE_RUNTIME(DRT_InstantiateType, args);
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(InstantiateTypeArgumentsTOS, A_D);
+ RawTypeArguments* type_arguments =
+ static_cast<RawTypeArguments*>(LOAD_CONSTANT(rD));
+
+ RawObject* instantiator = SP[0];
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ if (rA == 0 || null_value != instantiator) {
+ // First lookup in the cache.
+ RawArray* instantiations = type_arguments->ptr()->instantiations_;
+ for (intptr_t i = 0;
+ instantiations->ptr()->data()[i] != NULL; // kNoInstantiator
+ i += 2) {
+ if (instantiations->ptr()->data()[i] == instantiator) {
+ // Found in the cache.
+ SP[0] = instantiations->ptr()->data()[i + 1];
+ goto InstantiateTypeArgumentsTOSDone;
+ }
+ }
+
+ // Cache lookup failed, call runtime.
+ SP[1] = type_arguments;
+ SP[2] = instantiator;
+
+ Exit(thread, FP, SP + 3, pc);
+ NativeArguments args(thread, 2, SP + 1, SP);
+ INVOKE_RUNTIME(DRT_InstantiateTypeArguments, args);
+ }
+
+ InstantiateTypeArgumentsTOSDone:
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Throw, A);
+ {
+ SP[1] = 0; // Space for result.
+ Exit(thread, FP, SP + 2, pc);
+ if (rA == 0) { // Throw
+ NativeArguments args(thread, 1, SP, SP + 1);
+ INVOKE_RUNTIME(DRT_Throw, args);
+ } else { // ReThrow
+ NativeArguments args(thread, 2, SP - 1, SP + 1);
+ INVOKE_RUNTIME(DRT_ReThrow, args);
+ }
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Drop1, 0);
+ SP--;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Drop, 0);
+ SP -= rA;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DropR, 0);
+ RawObject* result = SP[0];
+ SP -= rA;
+ SP[0] = result;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadConstant, A_D);
+ FP[rA] = LOAD_CONSTANT(rD);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(PushConstant, __D);
+ *++SP = LOAD_CONSTANT(rD);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Push, A_X);
+ *++SP = FP[rD];
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Move, A_X);
+ FP[rA] = FP[rD];
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreLocal, A_X);
+ FP[rD] = *SP;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(PopLocal, A_X);
+ FP[rD] = *SP--;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(MoveSpecial, A_D);
+ FP[rA] = special_[rD];
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(BooleanNegateTOS, 0);
+ SP[0] = (SP[0] == true_value) ? false_value : true_value;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StaticCall, A_D);
+
+ // Check if single stepping.
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+
+ // Invoke target function.
+ {
+ const uint16_t argc = rA;
+ RawObject** call_base = SP - argc;
+ RawObject** call_top = SP; // *SP contains function
+ argdesc = static_cast<RawArray*>(LOAD_CONSTANT(rD));
+ Invoke(thread, call_base, call_top, &pp, &pc, &FP, &SP);
+ }
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(InstanceCall, A_D);
+
+ // Check if single stepping.
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+
+ {
+ const uint16_t argc = rA;
+ const uint16_t kidx = rD;
+
+ RawObject** call_base = SP - argc + 1;
+ RawObject** call_top = SP + 1;
+ InstanceCall1(thread,
+ static_cast<RawICData*>(LOAD_CONSTANT(kidx)),
+ call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
+ }
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(InstanceCall2, A_D);
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+
+ {
+ const uint16_t argc = rA;
+ const uint16_t kidx = rD;
+
+ RawObject** call_base = SP - argc + 1;
+ RawObject** call_top = SP + 1;
+ InstanceCall2(thread,
+ static_cast<RawICData*>(LOAD_CONSTANT(kidx)),
+ call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
+ }
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(InstanceCall3, A_D);
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+
+ {
+ const uint16_t argc = rA;
+ const uint16_t kidx = rD;
+
+ RawObject** call_base = SP - argc + 1;
+ RawObject** call_top = SP + 1;
+ InstanceCall3(thread,
+ static_cast<RawICData*>(LOAD_CONSTANT(kidx)),
+ call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
+ }
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(NativeBootstrapCall, 0);
+ RawFunction* function = FrameFunction(FP);
+ RawObject** incoming_args =
+ (function->ptr()->num_optional_parameters_ == 0)
+ ? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
+ : FP;
+
+ SimulatorBootstrapNativeCall native_target =
+ reinterpret_cast<SimulatorBootstrapNativeCall>(SP[-1]);
+ intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
+ SP[-0] = 0; // Note: argc_tag is not smi-tagged.
+ SP[-1] = null_value;
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
+ INVOKE_NATIVE(native_target, args);
+ SP -= 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(NativeCall, 0);
+ RawFunction* function = FrameFunction(FP);
+ RawObject** incoming_args =
+ (function->ptr()->num_optional_parameters_ == 0)
+ ? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
+ : FP;
+
+ Dart_NativeFunction native_target =
+ reinterpret_cast<Dart_NativeFunction>(SP[-1]);
+ intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
+ SP[-0] = 0; // argc_tag is not smi tagged!
+ SP[-1] = null_value;
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
+ INVOKE_NATIVE_WRAPPER(native_target, args);
+ SP -= 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(AddTOS, A_B_C);
+ SMI_FASTPATH_TOS(intptr_t, SignedAddWithOverflow);
+ DISPATCH();
+ }
+ {
+ BYTECODE(SubTOS, A_B_C);
+ SMI_FASTPATH_TOS(intptr_t, SignedSubWithOverflow);
+ DISPATCH();
+ }
+ {
+ BYTECODE(MulTOS, A_B_C);
+ SMI_FASTPATH_TOS(intptr_t, SMI_MUL);
+ DISPATCH();
+ }
+ {
+ BYTECODE(BitOrTOS, A_B_C);
+ SMI_FASTPATH_TOS(intptr_t, SMI_BITOR);
+ DISPATCH();
+ }
+ {
+ BYTECODE(BitAndTOS, A_B_C);
+ SMI_FASTPATH_TOS(intptr_t, SMI_BITAND);
+ DISPATCH();
+ }
+ {
+ BYTECODE(EqualTOS, A_B_C);
+ SMI_FASTPATH_TOS(RawObject*, SMI_EQ);
+ DISPATCH();
+ }
+ {
+ BYTECODE(LessThanTOS, A_B_C);
+ SMI_FASTPATH_TOS(RawObject*, SMI_LT);
+ DISPATCH();
+ }
+ {
+ BYTECODE(GreaterThanTOS, A_B_C);
+ SMI_FASTPATH_TOS(RawObject*, SMI_GT);
+ DISPATCH();
+ }
+
+ // Return and return like instructions (Instrinsic).
+ {
+ RawObject* result; // result to return to the caller.
+
+ BYTECODE(Intrinsic, A);
+ // Try invoking intrinsic handler. If it succeeds (returns true)
+ // then just return the value it returned to the caller.
+ result = null_value;
+ if (!intrinsics_[rA](thread, FP, &result)) {
+ DISPATCH();
+ }
+ goto ReturnImpl;
+
+ BYTECODE(Return, A);
+ result = FP[rA];
+ goto ReturnImpl;
+
+ BYTECODE(ReturnTOS, 0);
+ result = *SP;
+ // Fall through to the ReturnImpl.
+
+ ReturnImpl:
+ // Restore caller PC.
+ pc = SavedCallerPC(FP);
+
+ // Check if it is a fake PC marking the entry frame.
+ if ((reinterpret_cast<uword>(pc) & 2) != 0) {
+ const intptr_t argc = reinterpret_cast<uword>(pc) >> 2;
+ fp_ = sp_ =
+ reinterpret_cast<RawObject**>(FrameArguments(FP, argc + 1)[0]);
+ thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_));
+ thread->set_top_resource(top_resource);
+ thread->set_vm_tag(vm_tag);
+ return result;
+ }
+
+ // Look at the caller to determine how many arguments to pop.
+ const uint8_t argc = Bytecode::DecodeArgc(pc[-1]);
+
+ // Restore SP, FP and PP. Push result and dispatch.
+ SP = FrameArguments(FP, argc);
+ FP = SavedCallerFP(FP);
+ pp = FrameCode(FP)->ptr()->object_pool_->ptr();
+ *SP = result;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreStaticTOS, A_D);
+ RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
+ RawInstance* value = static_cast<RawInstance*>(*SP--);
+ field->StorePointer(&field->ptr()->value_.static_value_, value);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(PushStatic, A_D);
+ RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
+ // Note: field is also on the stack, hence no increment.
+ *SP = field->ptr()->value_.static_value_;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreField, A_B_C);
+ const uint16_t offset_in_words = rB;
+ const uint16_t value_reg = rC;
+
+ RawInstance* instance = reinterpret_cast<RawInstance*>(FP[rA]);
+ RawObject* value = reinterpret_cast<RawObject*>(FP[value_reg]);
+
+ instance->StorePointer(
+ reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
+ value);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreFieldTOS, A_D);
+ const uint16_t offset_in_words = rD;
+ RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
+ RawObject* value = reinterpret_cast<RawObject*>(SP[0]);
+ SP -= 2; // Drop instance and value.
+ instance->StorePointer(
+ reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
+ value);
+
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadField, A_B_C);
+ const uint16_t instance_reg = rB;
+ const uint16_t offset_in_words = rC;
+ RawInstance* instance = reinterpret_cast<RawInstance*>(FP[instance_reg]);
+ FP[rA] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadFieldTOS, A_D);
+ const uint16_t offset_in_words = rD;
+ RawInstance* instance = static_cast<RawInstance*>(SP[0]);
+ SP[0] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(InitStaticTOS, A);
+ RawField* field = static_cast<RawField*>(*SP--);
+ RawObject* value = field->ptr()->value_.static_value_;
+ if ((value == Object::sentinel().raw()) ||
+ (value == Object::transition_sentinel().raw())) {
+ // Note: SP[1] already contains the field object.
+ SP[2] = 0;
+ Exit(thread, FP, SP + 3, pc);
+ NativeArguments args(thread, 1, SP + 1, SP + 2);
+ INVOKE_RUNTIME(DRT_InitStaticField, args);
+ }
+ DISPATCH();
+ }
+
+ // TODO(vegorov) allocation bytecodes can benefit from the new-space
+ // allocation fast-path that does not transition into the runtime system.
+ {
+ BYTECODE(AllocateContext, A_D);
+ const uint16_t num_context_variables = rD;
+ {
+ *++SP = 0;
+ SP[1] = Smi::New(num_context_variables);
+ Exit(thread, FP, SP + 2, pc);
+ NativeArguments args(thread, 1, SP + 1, SP);
+ INVOKE_RUNTIME(DRT_AllocateContext, args);
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(CloneContext, A);
+ {
+ SP[1] = SP[0]; // Context to clone.
+ Exit(thread, FP, SP + 2, pc);
+ NativeArguments args(thread, 1, SP + 1, SP);
+ INVOKE_RUNTIME(DRT_CloneContext, args);
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Allocate, A_D);
+ SP[1] = 0; // Space for the result.
+ SP[2] = LOAD_CONSTANT(rD); // Class object.
+ SP[3] = null_value; // Type arguments.
+ Exit(thread, FP, SP + 4, pc);
+ NativeArguments args(thread, 2, SP + 2, SP + 1);
+ INVOKE_RUNTIME(DRT_AllocateObject, args);
+ SP++; // Result is in SP[1].
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(AllocateT, 0);
+ SP[1] = SP[-0]; // Class object.
+ SP[2] = SP[-1]; // Type arguments
+ Exit(thread, FP, SP + 3, pc);
+ NativeArguments args(thread, 2, SP + 1, SP - 1);
+ INVOKE_RUNTIME(DRT_AllocateObject, args);
+ SP -= 1; // Result is in SP - 1.
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(CreateArrayTOS, 0);
+ SP[1] = SP[-0]; // Length.
+ SP[2] = SP[-1]; // Type.
+ Exit(thread, FP, SP + 3, pc);
+ NativeArguments args(thread, 2, SP + 1, SP - 1);
+ INVOKE_RUNTIME(DRT_AllocateArray, args);
+ SP -= 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(AssertAssignable, A_D); // Stack: instance, type args, type, name
+ RawObject** args = SP - 3;
+ if (args[0] != null_value) {
+ RawSubtypeTestCache* cache =
+ static_cast<RawSubtypeTestCache*>(LOAD_CONSTANT(rD));
+ if (cache != null_value) {
+ RawInstance* instance = static_cast<RawInstance*>(args[0]);
+ RawTypeArguments* instantiator_type_arguments =
+ static_cast<RawTypeArguments*>(args[1]);
+
+ const intptr_t cid = SimulatorHelpers::GetClassId(instance);
+
+ RawTypeArguments* instance_type_arguments =
+ static_cast<RawTypeArguments*>(null_value);
+ RawObject* instance_cid_or_function;
+ if (cid == kClosureCid) {
+ RawClosure* closure = static_cast<RawClosure*>(instance);
+ instance_type_arguments = closure->ptr()->type_arguments_;
+ instance_cid_or_function = closure->ptr()->function_;
+ } else {
+ instance_cid_or_function = Smi::New(cid);
+
+ RawClass* instance_class =
+ thread->isolate()->class_table()->At(cid);
+ if (instance_class->ptr()->num_type_arguments_ < 0) {
+ goto AssertAssignableCallRuntime;
+ } else if (instance_class->ptr()->num_type_arguments_ > 0) {
+ instance_type_arguments = reinterpret_cast<RawTypeArguments**>(
+ instance
+ ->ptr())[instance_class->ptr()
+ ->type_arguments_field_offset_in_words_];
+ }
+ }
+
+ for (RawObject** entries = cache->ptr()->cache_->ptr()->data();
+ entries[0] != null_value;
+ entries += SubtypeTestCache::kTestEntryLength) {
+ if ((entries[SubtypeTestCache::kInstanceClassIdOrFunction] ==
+ instance_cid_or_function) &&
+ (entries[SubtypeTestCache::kInstanceTypeArguments] ==
+ instance_type_arguments) &&
+ (entries[SubtypeTestCache::kInstantiatorTypeArguments] ==
+ instantiator_type_arguments)) {
+ if (true_value == entries[SubtypeTestCache::kTestResult]) {
+ goto AssertAssignableOk;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ AssertAssignableCallRuntime:
+ SP[1] = args[0]; // instance
+ SP[2] = args[2]; // type
+ SP[3] = args[1]; // type args
+ SP[4] = args[3]; // name
+ SP[5] = cache;
+ Exit(thread, FP, SP + 6, pc);
+ NativeArguments args(thread, 5, SP + 1, SP - 3);
+ INVOKE_RUNTIME(DRT_TypeCheck, args);
+ }
+
+ AssertAssignableOk:
+ SP -= 3;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(AssertBoolean, A);
+ RawObject* value = SP[0];
+ if (rA) { // Should we perform type check?
+ if ((value == true_value) || (value == false_value)) {
+ goto AssertBooleanOk;
+ }
+ } else if (value != null_value) {
+ goto AssertBooleanOk;
+ }
+
+ // Assertion failed.
+ {
+ SP[1] = SP[0]; // instance
+ Exit(thread, FP, SP + 2, pc);
+ NativeArguments args(thread, 1, SP + 1, SP);
+ INVOKE_RUNTIME(DRT_NonBoolTypeError, args);
+ }
+
+ AssertBooleanOk:
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfEqStrictTOS, A_D);
+ SP -= 2;
+ if (SP[1] != SP[2]) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfNeStrictTOS, A_D);
+ SP -= 2;
+ if (SP[1] == SP[2]) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfEqStrictNumTOS, A_D);
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+
+ SP -= 2;
+ if (!SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfNeStrictNumTOS, A_D);
+ if (thread->isolate()->single_step()) {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments args(thread, 0, NULL, NULL);
+ INVOKE_RUNTIME(DRT_SingleStepHandler, args);
+ }
+
+ SP -= 2;
+ if (SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Jump, 0);
+ const int32_t target = static_cast<int32_t>(op) >> 8;
+ pc += (target - 1);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreIndexedTOS, 0);
+ SP -= 3;
+ RawArray* array = static_cast<RawArray*>(SP[1]);
+ RawSmi* index = static_cast<RawSmi*>(SP[2]);
+ RawObject* value = SP[3];
+ ASSERT(array->GetClassId() == kArrayCid);
+ ASSERT(!index->IsHeapObject());
+ array->StorePointer(array->ptr()->data() + Smi::Value(index), value);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Trap, 0);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ // Helper used to handle noSuchMethod on closures.
+ {
+ ClosureNoSuchMethod:
+#if defined(DEBUG)
+ function_h ^= FrameFunction(FP);
+ ASSERT(function_h.IsClosureFunction());
+#endif
+
+ // Restore caller context as we are going to throw NoSuchMethod.
+ pc = SavedCallerPC(FP);
+
+ const bool has_dart_caller = (reinterpret_cast<uword>(pc) & 2) == 0;
+ const intptr_t argc = has_dart_caller
+ ? Bytecode::DecodeArgc(pc[-1])
+ : (reinterpret_cast<uword>(pc) >> 2);
+
+ SP = FrameArguments(FP, 0);
+ RawObject** args = SP - argc;
+ FP = SavedCallerFP(FP);
+ if (has_dart_caller) {
+ pp = FrameCode(FP)->ptr()->object_pool_->ptr();
+ }
+
+ *++SP = null_value;
+ *++SP = args[0]; // Closure object.
+ *++SP = argdesc;
+ *++SP = null_value; // Array of arguments (will be filled).
+
+ // Allocate array of arguments.
+ {
+ SP[1] = Smi::New(argc); // length
+ SP[2] = null_value; // type
+ Exit(thread, FP, SP + 3, pc);
+ NativeArguments native_args(thread, 2, SP + 1, SP);
+ INVOKE_RUNTIME(DRT_AllocateArray, native_args);
+
+ // Copy arguments into the newly allocated array.
+ RawArray* array = static_cast<RawArray*>(SP[0]);
+ ASSERT(array->GetClassId() == kArrayCid);
+ for (intptr_t i = 0; i < argc; i++) {
+ array->ptr()->data()[i] = args[i];
+ }
+ }
+
+ // Invoke noSuchMethod passing down closure, argument descriptor and
+ // array of arguments.
+ {
+ Exit(thread, FP, SP + 1, pc);
+ NativeArguments native_args(thread, 3, SP - 2, SP - 3);
+ INVOKE_RUNTIME(DRT_InvokeClosureNoSuchMethod, native_args);
+ UNREACHABLE();
+ }
+
+ DISPATCH();
+ }
+
+ // Single dispatch point used by exception handling macros.
+ {
+ DispatchAfterException:
+ DISPATCH();
+ }
+
+ UNREACHABLE();
+ return 0;
+}
+
+void Simulator::Longjmp(uword pc,
+ uword sp,
+ uword fp,
+ RawObject* raw_exception,
+ RawObject* raw_stacktrace,
+ Thread* thread) {
+ // Walk over all setjmp buffers (simulated --> C++ transitions)
+ // and try to find the setjmp associated with the simulated stack pointer.
+ SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
+ while ((buf->link() != NULL) && (buf->link()->fp() > fp)) {
+ buf = buf->link();
+ }
+ ASSERT(buf != NULL);
+ ASSERT(last_setjmp_buffer() == buf);
+
+ // The C++ caller has not cleaned up the stack memory of C++ frames.
+ // Prepare for unwinding frames by destroying all the stack resources
+ // in the previous C++ frames.
+ StackResource::Unwind(thread);
+
+ // Set the tag.
+ thread->set_vm_tag(VMTag::kDartTagId);
+ // Clear top exit frame.
+ thread->set_top_exit_frame_info(0);
+
+ ASSERT(raw_exception != Object::null());
+ sp_ = reinterpret_cast<RawObject**>(sp);
+ fp_ = reinterpret_cast<RawObject**>(fp);
+ pc_ = pc;
+ special_[kExceptionSpecialIndex] = raw_exception;
+ special_[kStacktraceSpecialIndex] = raw_stacktrace;
+ buf->Longjmp();
+ UNREACHABLE();
+}
+
+} // namespace dart
+
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/simulator_dbc.h b/runtime/vm/simulator_dbc.h
new file mode 100644
index 0000000..c1d3ff9a
--- /dev/null
+++ b/runtime/vm/simulator_dbc.h
@@ -0,0 +1,182 @@
+// Copyright (c) 2016, 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_SIMULATOR_DBC_H_
+#define VM_SIMULATOR_DBC_H_
+
+#ifndef VM_SIMULATOR_H_
+#error Do not include simulator_dbc.h directly; use simulator.h.
+#endif
+
+#include "vm/constants_dbc.h"
+#include "vm/method_recognizer.h"
+
+namespace dart {
+
+class Isolate;
+class RawObject;
+class SimulatorSetjmpBuffer;
+class Thread;
+class Code;
+class Array;
+class RawICData;
+class RawArray;
+class RawObjectPool;
+class RawFunction;
+
+// Simulator intrinsic handler. It is invoked on entry to the intrinsified
+// function via Intrinsic bytecode before the frame is setup.
+// If the handler returns true then Intrinsic bytecode works as a return
+// instruction returning the value in result. Otherwise interpreter proceeds to
+// execute the body of the function.
+typedef bool (*IntrinsicHandler)(Thread* thread,
+ RawObject** FP,
+ RawObject** result);
+
+
+class Simulator {
+ public:
+ static const uword kSimulatorStackUnderflowSize = 0x80;
+
+ Simulator();
+ ~Simulator();
+
+ // The currently executing Simulator instance, which is associated to the
+ // current isolate
+ static Simulator* Current();
+
+ // Accessors to the internal simulator stack base and top.
+ uword StackBase() const { return reinterpret_cast<uword>(stack_); }
+ uword StackTop() const;
+
+ // The isolate's top_exit_frame_info refers to a Dart frame in the simulator
+ // stack. The simulator's top_exit_frame_info refers to a C++ frame in the
+ // native stack.
+ uword top_exit_frame_info() const { return top_exit_frame_info_; }
+ void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; }
+
+ // Call on program start.
+ static void InitOnce();
+
+ RawObject* Call(const Code& code,
+ const Array& arguments_descriptor,
+ const Array& arguments,
+ Thread* thread);
+
+ void Longjmp(uword pc,
+ uword sp,
+ uword fp,
+ RawObject* raw_exception,
+ RawObject* raw_stacktrace,
+ Thread* thread);
+
+ uword get_sp() const {
+ return reinterpret_cast<uword>(sp_);
+ }
+
+ enum IntrinsicId {
+#define V(test_class_name, test_function_name, enum_name, fp) \
+ k##enum_name##Intrinsic,
+ ALL_INTRINSICS_LIST(V)
+ GRAPH_INTRINSICS_LIST(V)
+#undef V
+ kIntrinsicCount,
+ };
+
+ static bool IsSupportedIntrinsic(IntrinsicId id) {
+ return intrinsics_[id] != NULL;
+ }
+
+ enum SpecialIndex {
+ kExceptionSpecialIndex,
+ kStacktraceSpecialIndex,
+ kSpecialIndexCount
+ };
+
+ private:
+ uintptr_t* stack_;
+
+ RawObject** fp_;
+ RawObject** sp_;
+ uword pc_;
+
+ SimulatorSetjmpBuffer* last_setjmp_buffer_;
+ uword top_exit_frame_info_;
+
+ RawObject* special_[kSpecialIndexCount];
+
+ static IntrinsicHandler intrinsics_[kIntrinsicCount];
+
+ void Exit(Thread* thread,
+ RawObject** base,
+ RawObject** exit_frame,
+ uint32_t* pc);
+
+ void CallRuntime(Thread* thread,
+ RawObject** base,
+ RawObject** exit_frame,
+ uint32_t* pc,
+ intptr_t argc_tag,
+ RawObject** args,
+ RawObject** result,
+ uword target);
+
+ void Invoke(Thread* thread,
+ RawObject** call_base,
+ RawObject** call_top,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** B,
+ RawObject*** SP);
+
+ void InlineCacheMiss(int checked_args,
+ Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** top,
+ uint32_t* pc,
+ RawObject** B, RawObject** SP);
+
+ void InstanceCall1(Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** call_top,
+ RawArray** argdesc,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** B, RawObject*** SP);
+
+ void InstanceCall2(Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** call_top,
+ RawArray** argdesc,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** B, RawObject*** SP);
+
+ void InstanceCall3(Thread* thread,
+ RawICData* icdata,
+ RawObject** call_base,
+ RawObject** call_top,
+ RawArray** argdesc,
+ RawObjectPool** pp,
+ uint32_t** pc,
+ RawObject*** B, RawObject*** SP);
+
+ // Longjmp support for exceptions.
+ SimulatorSetjmpBuffer* last_setjmp_buffer() {
+ return last_setjmp_buffer_;
+ }
+ void set_last_setjmp_buffer(SimulatorSetjmpBuffer* buffer) {
+ last_setjmp_buffer_ = buffer;
+ }
+
+ friend class SimulatorSetjmpBuffer;
+ DISALLOW_COPY_AND_ASSIGN(Simulator);
+};
+
+} // namespace dart
+
+#endif // VM_SIMULATOR_DBC_H_
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 244b331..d23c755 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -43,7 +43,6 @@
// The runtime then does a Longjmp on that buffer to return to the simulator.
class SimulatorSetjmpBuffer {
public:
- int Setjmp() { return setjmp(buffer_); }
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
@@ -1257,7 +1256,7 @@
ASSERT(sizeof(NativeArguments) == 4*kWordSize);
arguments.thread_ = reinterpret_cast<Thread*>(get_register(A0));
arguments.argc_tag_ = get_register(A1);
- arguments.argv_ = reinterpret_cast<RawObject*(*)[]>(get_register(A2));
+ arguments.argv_ = reinterpret_cast<RawObject**>(get_register(A2));
arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3));
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index 8d10c3f..700b1f5 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -58,6 +58,10 @@
int64_t get_dregister_bits(DRegister freg) const;
double get_dregister(DRegister freg) const;
+ int32_t get_sp() const {
+ return get_register(SPREG);
+ }
+
// Accessor for the pc.
void set_pc(int32_t value) { pc_ = value; }
int32_t get_pc() const { return pc_; }
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index c455d30..4729798 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -542,7 +542,7 @@
if (kind_ == Snapshot::kFull) {
result->SetCanonical();
} else {
- *result = result->CheckAndCanonicalize(NULL);
+ *result = result->CheckAndCanonicalize(thread(), NULL);
ASSERT(!result->IsNull());
}
}
@@ -647,7 +647,6 @@
}
}
-
// Validate the class table.
#if defined(DEBUG)
isolate->ValidateClassTable();
@@ -655,8 +654,17 @@
// Setup native resolver for bootstrap impl.
Bootstrap::SetupNativeResolver();
- return ApiError::null();
}
+
+ Class& cls = Class::Handle(thread->zone());
+ for (intptr_t i = 0; i < backward_references_->length(); i++) {
+ if ((*backward_references_)[i].reference()->IsClass()) {
+ cls ^= (*backward_references_)[i].reference()->raw();
+ cls.RehashConstants(thread->zone());
+ }
+ }
+
+ return ApiError::null();
}
@@ -1188,7 +1196,7 @@
}
-void InstructionsWriter::WriteAssembly() {
+void AssemblyInstructionsWriter::Write() {
Zone* zone = Thread::Current()->zone();
// Handlify collected raw pointers as building the names below
@@ -1204,12 +1212,12 @@
data.obj_ = &Object::Handle(zone, data.raw_obj_);
}
- stream_.Print(".text\n");
- stream_.Print(".globl _kInstructionsSnapshot\n");
+ assembly_stream_.Print(".text\n");
+ assembly_stream_.Print(".globl _kInstructionsSnapshot\n");
// Start snapshot at page boundary.
ASSERT(VirtualMemory::PageSize() >= OS::kMaxPreferredCodeAlignment);
- stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
- stream_.Print("_kInstructionsSnapshot:\n");
+ assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
+ assembly_stream_.Print("_kInstructionsSnapshot:\n");
// This head also provides the gap to make the instructions snapshot
// look like a HeapPage.
@@ -1233,16 +1241,17 @@
owner = code.owner();
if (owner.IsNull()) {
const char* name = StubCode::NameOfStub(insns.EntryPoint());
- stream_.Print("Precompiled_Stub_%s:\n", name);
+ assembly_stream_.Print("Precompiled_Stub_%s:\n", name);
} else if (owner.IsClass()) {
str = Class::Cast(owner).Name();
const char* name = str.ToCString();
EnsureIdentifier(const_cast<char*>(name));
- stream_.Print("Precompiled_AllocationStub_%s_%" Pd ":\n", name, i);
+ assembly_stream_.Print("Precompiled_AllocationStub_%s_%" Pd ":\n",
+ name, i);
} else if (owner.IsFunction()) {
const char* name = Function::Cast(owner).ToQualifiedCString();
EnsureIdentifier(const_cast<char*>(name));
- stream_.Print("Precompiled_%s_%" Pd ":\n", name, i);
+ assembly_stream_.Print("Precompiled_%s_%" Pd ":\n", name, i);
} else {
UNREACHABLE();
}
@@ -1268,24 +1277,25 @@
}
}
#if defined(TARGET_OS_LINUX)
- stream_.Print(".section .rodata\n");
+ assembly_stream_.Print(".section .rodata\n");
#elif defined(TARGET_OS_MACOS)
- stream_.Print(".const\n");
+ assembly_stream_.Print(".const\n");
#else
// Unsupported platform.
UNREACHABLE();
#endif
- stream_.Print(".globl _kDataSnapshot\n");
+ assembly_stream_.Print(".globl _kDataSnapshot\n");
// Start snapshot at page boundary.
- stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
- stream_.Print("_kDataSnapshot:\n");
+ assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
+ assembly_stream_.Print("_kDataSnapshot:\n");
WriteWordLiteral(next_object_offset_); // Data length.
COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment);
- stream_.Print(".balign %" Pd ", 0\n", OS::kMaxPreferredCodeAlignment);
+ assembly_stream_.Print(".balign %" Pd ", 0\n",
+ OS::kMaxPreferredCodeAlignment);
for (intptr_t i = 0; i < objects_.length(); i++) {
const Object& obj = *objects_[i].obj_;
- stream_.Print("Precompiled_Obj_%d:\n", i);
+ assembly_stream_.Print("Precompiled_Obj_%d:\n", i);
NoSafepointScope no_safepoint;
uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag;
@@ -1306,6 +1316,84 @@
}
+void BlobInstructionsWriter::Write() {
+ Zone* zone = Thread::Current()->zone();
+
+ // Handlify collected raw pointers as building the names below
+ // will allocate on the Dart heap.
+ for (intptr_t i = 0; i < instructions_.length(); i++) {
+ InstructionsData& data = instructions_[i];
+ data.insns_ = &Instructions::Handle(zone, data.raw_insns_);
+ ASSERT(data.raw_code_ != NULL);
+ data.code_ = &Code::Handle(zone, data.raw_code_);
+ }
+ for (intptr_t i = 0; i < objects_.length(); i++) {
+ ObjectData& data = objects_[i];
+ data.obj_ = &Object::Handle(zone, data.raw_obj_);
+ }
+
+ // This head also provides the gap to make the instructions snapshot
+ // look like a HeapPage.
+ intptr_t instructions_length = next_offset_;
+ instructions_blob_stream_.WriteWord(instructions_length);
+ intptr_t header_words = InstructionsSnapshot::kHeaderSize / sizeof(uword);
+ for (intptr_t i = 1; i < header_words; i++) {
+ instructions_blob_stream_.WriteWord(0);
+ }
+
+ for (intptr_t i = 0; i < instructions_.length(); i++) {
+ const Instructions& insns = *instructions_[i].insns_;
+
+ {
+ // 2. Write from the entry point to the end.
+ NoSafepointScope no_safepoint;
+ uword beginning = reinterpret_cast<uword>(insns.raw()) - kHeapObjectTag;
+ uword entry = beginning + Instructions::HeaderSize();
+ uword payload_size = insns.size();
+ payload_size = Utils::RoundUp(payload_size, OS::PreferredCodeAlignment());
+ uword end = entry + payload_size;
+
+ ASSERT(Utils::IsAligned(beginning, sizeof(uint64_t)));
+ ASSERT(Utils::IsAligned(entry, sizeof(uint64_t)));
+ ASSERT(Utils::IsAligned(end, sizeof(uint64_t)));
+
+ for (uword* cursor = reinterpret_cast<uword*>(entry);
+ cursor < reinterpret_cast<uword*>(end);
+ cursor++) {
+ instructions_blob_stream_.WriteWord(*cursor);
+ }
+ }
+ }
+
+ rodata_blob_stream_.WriteWord(next_object_offset_); // Data length.
+ COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment);
+ while (!Utils::IsAligned(rodata_blob_stream_.bytes_written(),
+ OS::kMaxPreferredCodeAlignment)) {
+ rodata_blob_stream_.WriteWord(0);
+ }
+
+ for (intptr_t i = 0; i < objects_.length(); i++) {
+ const Object& obj = *objects_[i].obj_;
+
+ NoSafepointScope no_safepoint;
+ uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag;
+ uword end = start + obj.raw()->Size();
+
+ // Write object header with the mark and VM heap bits set.
+ uword marked_tags = obj.raw()->ptr()->tags_;
+ marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags);
+ marked_tags = RawObject::MarkBit::update(true, marked_tags);
+ rodata_blob_stream_.WriteWord(marked_tags);
+ start += sizeof(uword);
+ for (uword* cursor = reinterpret_cast<uword*>(start);
+ cursor < reinterpret_cast<uword*>(end);
+ cursor++) {
+ rodata_blob_stream_.WriteWord(*cursor);
+ }
+ }
+}
+
+
uword InstructionsReader::GetInstructionsAt(int32_t offset) {
ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
return reinterpret_cast<uword>(instructions_buffer_) + offset;
@@ -1875,20 +1963,18 @@
FullSnapshotWriter::FullSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
uint8_t** isolate_snapshot_buffer,
- uint8_t** instructions_snapshot_buffer,
ReAlloc alloc,
+ InstructionsWriter* instructions_writer,
bool snapshot_code,
bool vm_isolate_is_symbolic)
: thread_(Thread::Current()),
vm_isolate_snapshot_buffer_(vm_isolate_snapshot_buffer),
isolate_snapshot_buffer_(isolate_snapshot_buffer),
- instructions_snapshot_buffer_(instructions_snapshot_buffer),
alloc_(alloc),
vm_isolate_snapshot_size_(0),
isolate_snapshot_size_(0),
- instructions_snapshot_size_(0),
forward_list_(NULL),
- instructions_writer_(NULL),
+ instructions_writer_(instructions_writer),
scripts_(Array::Handle(zone())),
symbol_table_(Array::Handle(zone())),
snapshot_code_(snapshot_code),
@@ -1927,12 +2013,6 @@
forward_list_ = new ForwardList(thread(), SnapshotWriter::FirstObjectId());
ASSERT(forward_list_ != NULL);
-
- if (instructions_snapshot_buffer != NULL) {
- instructions_writer_ = new InstructionsWriter(instructions_snapshot_buffer,
- alloc,
- kInitialSize);
- }
}
@@ -2051,8 +2131,7 @@
}
WriteIsolateFullSnapshot();
if (snapshot_code_) {
- instructions_writer_->WriteAssembly();
- instructions_snapshot_size_ = instructions_writer_->BytesWritten();
+ instructions_writer_->Write();
OS::Print("VMIsolate(CodeSize): %" Pd "\n", VmIsolateSnapshotSize());
OS::Print("Isolate(CodeSize): %" Pd "\n", IsolateSnapshotSize());
@@ -2069,12 +2148,12 @@
PrecompiledSnapshotWriter::PrecompiledSnapshotWriter(
uint8_t** vm_isolate_snapshot_buffer,
uint8_t** isolate_snapshot_buffer,
- uint8_t** instructions_snapshot_buffer,
- ReAlloc alloc)
+ ReAlloc alloc,
+ InstructionsWriter* instructions_writer)
: FullSnapshotWriter(vm_isolate_snapshot_buffer,
isolate_snapshot_buffer,
- instructions_snapshot_buffer,
alloc,
+ instructions_writer,
true, /* snapshot_code */
false /* vm_isolate_is_symbolic */) {
}
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 25dab12..f9822b8 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -844,31 +844,22 @@
class InstructionsWriter : public ZoneAllocated {
public:
- InstructionsWriter(uint8_t** buffer,
- ReAlloc alloc,
- intptr_t initial_size)
- : stream_(buffer, alloc, initial_size),
- next_offset_(InstructionsSnapshot::kHeaderSize),
+ InstructionsWriter()
+ : next_offset_(InstructionsSnapshot::kHeaderSize),
next_object_offset_(DataSnapshot::kHeaderSize),
- binary_size_(0),
instructions_(),
objects_() {
- ASSERT(buffer != NULL);
- ASSERT(alloc != NULL);
}
-
- // Size of the snapshot (assembly code).
- intptr_t BytesWritten() const { return stream_.bytes_written(); }
-
- intptr_t binary_size() { return binary_size_; }
+ virtual ~InstructionsWriter() { }
int32_t GetOffsetFor(RawInstructions* instructions, RawCode* code);
int32_t GetObjectOffsetFor(RawObject* raw_object);
- void WriteAssembly();
+ virtual void Write() = 0;
+ virtual intptr_t binary_size() = 0;
- private:
+ protected:
struct InstructionsData {
explicit InstructionsData(RawInstructions* insns,
RawCode* code,
@@ -896,24 +887,76 @@
};
};
+ intptr_t next_offset_;
+ intptr_t next_object_offset_;
+ GrowableArray<InstructionsData> instructions_;
+ GrowableArray<ObjectData> objects_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InstructionsWriter);
+};
+
+
+class AssemblyInstructionsWriter : public InstructionsWriter {
+ public:
+ AssemblyInstructionsWriter(uint8_t** assembly_buffer,
+ ReAlloc alloc,
+ intptr_t initial_size)
+ : InstructionsWriter(),
+ assembly_stream_(assembly_buffer, alloc, initial_size) {
+ }
+
+ virtual void Write();
+ virtual intptr_t binary_size() { return binary_size_; }
+
+ intptr_t AssemblySize() const { return assembly_stream_.bytes_written(); }
+
+ private:
void WriteWordLiteral(uword value) {
// Padding is helpful for comparing the .S with --disassemble.
#if defined(ARCH_IS_64_BIT)
- stream_.Print(".quad 0x%0.16" Px "\n", value);
+ assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
#else
- stream_.Print(".long 0x%0.8" Px "\n", value);
+ assembly_stream_.Print(".long 0x%0.8" Px "\n", value);
#endif
binary_size_ += sizeof(value);
}
- WriteStream stream_;
- intptr_t next_offset_;
- intptr_t next_object_offset_;
+ WriteStream assembly_stream_;
intptr_t binary_size_;
- GrowableArray<InstructionsData> instructions_;
- GrowableArray<ObjectData> objects_;
- DISALLOW_COPY_AND_ASSIGN(InstructionsWriter);
+ DISALLOW_COPY_AND_ASSIGN(AssemblyInstructionsWriter);
+};
+
+
+class BlobInstructionsWriter : public InstructionsWriter {
+ public:
+ BlobInstructionsWriter(uint8_t** instructions_blob_buffer,
+ uint8_t** rodata_blob_buffer,
+ ReAlloc alloc,
+ intptr_t initial_size)
+ : InstructionsWriter(),
+ instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
+ rodata_blob_stream_(rodata_blob_buffer, alloc, initial_size) {
+ }
+
+ virtual void Write();
+ virtual intptr_t binary_size() {
+ return InstructionsBlobSize() + RodataBlobSize();
+ }
+
+ intptr_t InstructionsBlobSize() const {
+ return instructions_blob_stream_.bytes_written();
+ }
+ intptr_t RodataBlobSize() const {
+ return rodata_blob_stream_.bytes_written();
+ }
+
+ private:
+ WriteStream instructions_blob_stream_;
+ WriteStream rodata_blob_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlobInstructionsWriter);
};
@@ -1070,8 +1113,8 @@
static const intptr_t kInitialSize = 64 * KB;
FullSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
uint8_t** isolate_snapshot_buffer,
- uint8_t** instructions_snapshot_buffer,
ReAlloc alloc,
+ InstructionsWriter* instructions_writer,
bool snapshot_code,
bool vm_isolate_is_symbolic);
~FullSnapshotWriter();
@@ -1098,9 +1141,6 @@
intptr_t IsolateSnapshotSize() const {
return isolate_snapshot_size_;
}
- intptr_t InstructionsSnapshotSize() const {
- return instructions_snapshot_size_;
- }
private:
// Writes a snapshot of the VM Isolate.
@@ -1112,11 +1152,9 @@
Thread* thread_;
uint8_t** vm_isolate_snapshot_buffer_;
uint8_t** isolate_snapshot_buffer_;
- uint8_t** instructions_snapshot_buffer_;
ReAlloc alloc_;
intptr_t vm_isolate_snapshot_size_;
intptr_t isolate_snapshot_size_;
- intptr_t instructions_snapshot_size_;
ForwardList* forward_list_;
InstructionsWriter* instructions_writer_;
Array& scripts_;
@@ -1132,8 +1170,8 @@
public:
PrecompiledSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
uint8_t** isolate_snapshot_buffer,
- uint8_t** instructions_snapshot_buffer,
- ReAlloc alloc);
+ ReAlloc alloc,
+ InstructionsWriter* instructions_writer);
~PrecompiledSnapshotWriter();
};
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 573addf..bf15a61 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1186,8 +1186,8 @@
{
FullSnapshotWriter writer(NULL,
&isolate_snapshot_buffer,
- NULL, /* instructions_snapshot_buffer */
&malloc_allocator,
+ NULL, /* instructions_writer */
false, /* snapshot_code */
true);
writer.WriteFullSnapshot();
@@ -1247,8 +1247,8 @@
{
FullSnapshotWriter writer(NULL,
&isolate_snapshot_buffer,
- NULL, /* instructions_snapshot_buffer */
&malloc_allocator,
+ NULL, /* instructions_writer */
false, /* snapshot_code */
true /* vm_isolate_is_symbolic */);
writer.WriteFullSnapshot();
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index ebfe69e..aac196b 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -69,6 +69,7 @@
void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
+#if !defined(TARGET_ARCH_DBC)
ASSERT(thread() == Thread::Current());
// Visit objects between SP and (FP - callee_save_area).
ASSERT(visitor != NULL);
@@ -76,10 +77,17 @@
RawObject** last = reinterpret_cast<RawObject**>(
fp() + (kExitLinkSlotFromEntryFp - 1) * kWordSize);
visitor->VisitPointers(first, last);
+#else
+ // On DBC stack is growing upwards which implies fp() <= sp().
+ RawObject** first = reinterpret_cast<RawObject**>(fp());
+ RawObject** last = reinterpret_cast<RawObject**>(sp());
+ visitor->VisitPointers(first, last);
+#endif
}
void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
+#if !defined(TARGET_ARCH_DBC)
// NOTE: This code runs while GC is in progress and runs within
// a NoHandleScope block. Hence it is not ok to use regular Zone or
// Scope handles. We use direct stack handles, the raw pointers in
@@ -159,6 +167,13 @@
RawObject** last = reinterpret_cast<RawObject**>(
fp() + (kFirstObjectSlotFromFp * kWordSize));
visitor->VisitPointers(first, last);
+#else
+ // On DBC stack grows upwards: fp() <= sp().
+ RawObject** first = reinterpret_cast<RawObject**>(
+ fp() + (kFirstObjectSlotFromFp * kWordSize));
+ RawObject** last = reinterpret_cast<RawObject**>(sp());
+ visitor->VisitPointers(first, last);
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -319,6 +334,7 @@
}
+#if !defined(TARGET_ARCH_DBC)
StackFrameIterator::StackFrameIterator(uword fp, uword sp, uword pc,
bool validate, Thread* thread)
: validate_(validate),
@@ -333,6 +349,7 @@
frames_.sp_ = sp;
frames_.pc_ = pc;
}
+#endif
StackFrame* StackFrameIterator::NextFrame() {
@@ -353,6 +370,7 @@
return NULL;
}
UnpoisonStack(frames_.fp_);
+#if !defined(TARGET_ARCH_DBC)
if (frames_.pc_ == 0) {
// Iteration starts from an exit frame given by its fp.
current_frame_ = NextExitFrame();
@@ -364,6 +382,12 @@
// Iteration starts from a Dart or stub frame given by its fp, sp, and pc.
current_frame_ = frames_.NextFrame(validate_);
}
+#else
+ // Iteration starts from an exit frame given by its fp. This is the only
+ // mode supported on DBC.
+ ASSERT(frames_.pc_ == 0);
+ current_frame_ = NextExitFrame();
+#endif // !defined(TARGET_ARCH_DBC)
return current_frame_;
}
ASSERT((validate_ == kDontValidateFrames) || current_frame_->IsValid());
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 2d1b12c..dac3e5f 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -19,6 +19,8 @@
#include "vm/stack_frame_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/stack_frame_mips.h"
+#elif defined(TARGET_ARCH_DBC)
+#include "vm/stack_frame_dbc.h"
#else
#error Unknown architecture.
#endif
@@ -101,10 +103,12 @@
uword GetCallerSp() const {
return fp() + (kCallerSpSlotFromFp * kWordSize);
}
+
uword GetCallerFp() const {
return *(reinterpret_cast<uword*>(
- fp() + (kSavedCallerFpSlotFromFp * kWordSize)));
+ fp() + (kSavedCallerFpSlotFromFp * kWordSize)));
}
+
uword GetCallerPc() const {
return *(reinterpret_cast<uword*>(
fp() + (kSavedCallerPcSlotFromFp * kWordSize)));
@@ -188,10 +192,12 @@
StackFrameIterator(uword last_fp, bool validate,
Thread* thread = Thread::Current());
+#if !defined(TARGET_ARCH_DBC)
// Iterator for iterating over all frames from the current frame (given by its
// fp, sp, and pc) to the first EntryFrame.
StackFrameIterator(uword fp, uword sp, uword pc, bool validate,
Thread* thread = Thread::Current());
+#endif
// Checks if a next frame exists.
bool HasNextFrame() const { return frames_.fp_ != 0; }
@@ -272,6 +278,8 @@
DartFrameIterator(uword last_fp,
Thread* thread = Thread::Current())
: frames_(last_fp, StackFrameIterator::kDontValidateFrames, thread) { }
+
+#if !defined(TARGET_ARCH_DBC)
DartFrameIterator(uword fp,
uword sp,
uword pc,
@@ -279,6 +287,8 @@
: frames_(fp, sp, pc,
StackFrameIterator::kDontValidateFrames, thread) {
}
+#endif
+
// Get next dart frame.
StackFrame* NextFrame() {
StackFrame* frame = frames_.NextFrame();
@@ -336,6 +346,27 @@
DISALLOW_COPY_AND_ASSIGN(InlinedFunctionsIterator);
};
+#if !defined(TARGET_ARCH_DBC)
+DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
+ return fp + (index * kWordSize);
+}
+
+
+DART_FORCE_INLINE static uword ParamAddress(uword fp, intptr_t reverse_index) {
+ return fp + (kParamEndSlotFromFp * kWordSize) + (reverse_index * kWordSize);
+}
+
+
+DART_FORCE_INLINE static bool IsCalleeFrameOf(uword fp, uword other_fp) {
+ return other_fp < fp;
+}
+
+// Value for stack limit that is used to cause an interrupt.
+// Note that on DBC stack is growing upwards so interrupt limit is 0 unlike
+// on all other architectures.
+static const uword kInterruptStackLimit = ~static_cast<uword>(0);
+#endif
+
} // namespace dart
#endif // VM_STACK_FRAME_H_
diff --git a/runtime/vm/stack_frame_dbc.h b/runtime/vm/stack_frame_dbc.h
new file mode 100644
index 0000000..a59a417
--- /dev/null
+++ b/runtime/vm/stack_frame_dbc.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2016, 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_STACK_FRAME_DBC_H_
+#define VM_STACK_FRAME_DBC_H_
+
+namespace dart {
+
+/* DBC Frame Layout
+
+IMPORTANT: On DBC stack is growing upwards which is different from all other
+architectures. This enables effecient addressing for locals via unsigned index.
+
+ | | <- TOS
+Callee frame | ... |
+ | saved FP | (FP of current frame)
+ | saved PC | (PC of current frame)
+ | code object |
+ | function object |
+ +--------------------+
+Current frame | ... T| <- SP of current frame
+ | ... T|
+ | first local T| <- FP of current frame
+ | caller's FP *|
+ | caller's PC *|
+ | code object T| (current frame's code object)
+ | function object T| (current frame's function object)
+ +--------------------+
+Caller frame | last parameter | <- SP of caller frame
+ | ... |
+
+ T against a slot indicates it needs to be traversed during GC.
+ * against a slot indicates that it can be traversed during GC
+ because it will look like a smi to the visitor.
+*/
+
+static const int kDartFrameFixedSize = 4; // Function, Code, PC, FP
+static const int kSavedPcSlotFromSp = 3;
+
+static const int kFirstObjectSlotFromFp = -4; // Used by GC to traverse stack.
+
+static const int kSavedCallerFpSlotFromFp = -1;
+static const int kSavedCallerPpSlotFromFp = kSavedCallerFpSlotFromFp;
+static const int kSavedCallerPcSlotFromFp = -2;
+static const int kCallerSpSlotFromFp = -kDartFrameFixedSize-1;
+static const int kPcMarkerSlotFromFp = -3;
+static const int kFunctionSlotFromFp = -4;
+
+// Note: These constants don't match actual DBC behavior. This is done because
+// setting kFirstLocalSlotFromFp to 0 breaks assumptions spread across the code.
+// Instead for the purposes of local variable allocation we pretend that DBC
+// behaves as other architectures (stack growing downwards) and later fix
+// these indices during code generation in the backend.
+static const int kParamEndSlotFromFp = 4; // One slot past last parameter.
+static const int kFirstLocalSlotFromFp = -1;
+
+
+DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
+ ASSERT(index != 0);
+ if (index > 0) {
+ return fp - index * kWordSize;
+ } else {
+ return fp - (index + 1) * kWordSize;
+ }
+}
+
+DART_FORCE_INLINE static uword ParamAddress(uword fp, intptr_t reverse_index) {
+ return fp - (kDartFrameFixedSize + reverse_index) * kWordSize;
+}
+
+DART_FORCE_INLINE static bool IsCalleeFrameOf(uword fp, uword other_fp) {
+ return other_fp > fp;
+}
+
+static const int kExitLinkSlotFromEntryFp = 0;
+
+// Value for stack limit that is used to cause an interrupt.
+// Note that on DBC stack is growing upwards so interrupt limit is 0 unlike
+// on all other architectures.
+static const uword kInterruptStackLimit = 0;
+
+} // namespace dart
+
+#endif // VM_STACK_FRAME_DBC_H_
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 6738a25..04ca4f4 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -85,30 +85,47 @@
bool StubCode::HasBeenInitialized() {
+#if !defined(TARGET_ARCH_DBC)
// Use JumpToExceptionHandler and InvokeDart as canaries.
const StubEntry* entry_1 = StubCode::JumpToExceptionHandler_entry();
const StubEntry* entry_2 = StubCode::InvokeDartCode_entry();
return (entry_1 != NULL) && (entry_2 != NULL);
+#else
+ return true;
+#endif
}
bool StubCode::InInvocationStub(uword pc) {
+#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
uword entry = StubCode::InvokeDartCode_entry()->EntryPoint();
uword size = StubCode::InvokeDartCodeSize();
return (pc >= entry) && (pc < (entry + size));
+#else
+ // On DBC we use a special marker PC to signify entry frame because there is
+ // no such thing as invocation stub.
+ return (pc & 2) != 0;
+#endif
}
bool StubCode::InJumpToExceptionHandlerStub(uword pc) {
+#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
uword entry = StubCode::JumpToExceptionHandler_entry()->EntryPoint();
uword size = StubCode::JumpToExceptionHandlerSize();
return (pc >= entry) && (pc < (entry + size));
+#else
+ // This stub does not exist on DBC.
+ return false;
+#endif
}
RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
+ // These stubs are not used by DBC.
+#if !defined(TARGET_ARCH_DBC)
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
@@ -169,11 +186,16 @@
}
}
return stub.raw();
+#endif
+ UNIMPLEMENTED();
+ return Code::null();
}
const StubEntry* StubCode::UnoptimizedStaticCallEntry(
intptr_t num_args_tested) {
+ // These stubs are not used by DBC.
+#if !defined(TARGET_ARCH_DBC)
switch (num_args_tested) {
case 0:
return ZeroArgsUnoptimizedStaticCall_entry();
@@ -185,6 +207,9 @@
UNIMPLEMENTED();
return NULL;
}
+#else
+ return NULL;
+#endif
}
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index fed306b..aa20321 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -18,9 +18,9 @@
class SnapshotReader;
class SnapshotWriter;
-
// List of stubs created in the VM isolate, these stubs are shared by different
// isolates running in this dart process.
+#if !defined(TARGET_ARCH_DBC)
#define VM_STUB_CODE_LIST(V) \
V(GetStackPointer) \
V(JumpToExceptionHandler) \
@@ -65,6 +65,13 @@
V(CallClosureNoSuchMethod) \
V(FrameAwaitingMaterialization) \
+#else
+#define VM_STUB_CODE_LIST(V) \
+ V(LazyCompile) \
+ V(FixCallersTarget) \
+
+#endif // !defined(TARGET_ARCH_DBC)
+
// 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,
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index e5a03c7..8e85852 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -625,8 +625,7 @@
__ b(&slow_case, GT);
const intptr_t cid = kArrayCid;
- __ MaybeTraceAllocation(cid, R4, &slow_case,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(cid, R4, &slow_case);
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ LoadImmediate(R9, fixed_size);
@@ -653,7 +652,7 @@
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ LoadAllocationStatsAddress(R3, cid, /* inline_isolate = */ false);
+ __ LoadAllocationStatsAddress(R3, cid);
__ str(NOTFP, Address(R8, Heap::TopOffset(space)));
__ add(R0, R0, Operand(kHeapObjectTag));
@@ -859,8 +858,7 @@
ASSERT(kSmiTagShift == 1);
__ bic(R2, R2, Operand(kObjectAlignment - 1));
- __ MaybeTraceAllocation(kContextCid, R8, &slow_case,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kContextCid, R8, &slow_case);
// Now allocate the object.
// R1: number of context variables.
// R2: object size.
@@ -891,7 +889,7 @@
// R2: object size.
// R3: next object start.
// R9: heap.
- __ LoadAllocationStatsAddress(R4, cid, /* inline_isolate = */ false);
+ __ LoadAllocationStatsAddress(R4, cid);
__ str(R3, Address(R9, Heap::TopOffset(space)));
__ add(R0, R0, Operand(kHeapObjectTag));
@@ -1083,7 +1081,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(R9, cls.id(), /* inline_isolate = */ false);
+ __ LoadAllocationStatsAddress(R9, cls.id());
// R0: new object start.
// R1: next object start.
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index bddf296..cb31d8e 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -652,8 +652,7 @@
__ b(&slow_case, GT);
const intptr_t cid = kArrayCid;
- __ MaybeTraceAllocation(kArrayCid, R4, &slow_case,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kArrayCid, R4, &slow_case);
Heap::Space space = Heap::SpaceForAllocation(cid);
__ LoadIsolate(R8);
@@ -694,8 +693,7 @@
// R8: heap.
__ StoreToOffset(R7, R8, Heap::TopOffset(space));
__ add(R0, R0, Operand(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, R3, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, R3, space);
// R0: new object start as a tagged pointer.
// R1: array element type.
@@ -919,8 +917,7 @@
ASSERT(kSmiTagShift == 1);
__ andi(R2, R2, Immediate(~(kObjectAlignment - 1)));
- __ MaybeTraceAllocation(kContextCid, R4, &slow_case,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kContextCid, R4, &slow_case);
// Now allocate the object.
// R1: number of context variables.
// R2: object size.
@@ -953,8 +950,7 @@
// R5: heap.
__ str(R3, Address(R5, Heap::TopOffset(space)));
__ add(R0, R0, Operand(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, R2, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, R2, space);
// Calculate the size tag.
// R0: new object.
@@ -1128,7 +1124,7 @@
__ b(&slow_case, CS); // Unsigned higher or equal.
}
__ str(R3, Address(R5, Heap::TopOffset(space)));
- __ UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
+ __ UpdateAllocationStats(cls.id(), space);
// R2: new object start.
// R3: next object start.
diff --git a/runtime/vm/stub_code_dbc.cc b/runtime/vm/stub_code_dbc.cc
new file mode 100644
index 0000000..0042f2d
--- /dev/null
+++ b/runtime/vm/stub_code_dbc.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/globals.h"
+#if defined(TARGET_ARCH_DBC)
+
+#include "vm/assembler.h"
+#include "vm/code_generator.h"
+#include "vm/cpu.h"
+#include "vm/compiler.h"
+#include "vm/dart_entry.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/heap.h"
+#include "vm/instructions.h"
+#include "vm/object_store.h"
+#include "vm/stack_frame.h"
+#include "vm/stub_code.h"
+#include "vm/tags.h"
+
+#define __ assembler->
+
+namespace dart {
+
+DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects.");
+DEFINE_FLAG(bool, use_slow_path, false,
+ "Set to true for debugging & verifying the slow paths.");
+DECLARE_FLAG(bool, trace_optimized_ic_calls);
+DECLARE_FLAG(int, optimization_counter_threshold);
+DECLARE_FLAG(bool, support_debugger);
+DECLARE_FLAG(bool, lazy_dispatchers);
+
+void StubCode::GenerateLazyCompileStub(Assembler* assembler) {
+ __ Compile();
+}
+
+
+// TODO(vegorov) Don't generate this stub.
+void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
+ __ Trap();
+}
+
+
+// TODO(vegorov) Don't generate these stubs.
+void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
+ const Class& cls) {
+ __ Trap();
+}
+
+
+// TODO(vegorov) Don't generate this stub.
+void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
+ __ Trap();
+}
+
+
+// Print the stop message.
+DEFINE_LEAF_RUNTIME_ENTRY(void, PrintStopMessage, 1, const char* message) {
+ OS::Print("Stop message: %s\n", message);
+}
+END_LEAF_RUNTIME_ENTRY
+
+
+} // namespace dart
+
+#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 2a4ed9b..772e39b 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -564,8 +564,7 @@
__ MaybeTraceAllocation(kArrayCid,
EAX,
&slow_case,
- Assembler::kFarJump,
- /* inline_isolate = */ false);
+ Assembler::kFarJump);
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ leal(EBX, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi.
@@ -597,8 +596,7 @@
__ movl(Address(EDI, Heap::TopOffset(space)), EBX);
__ subl(EBX, EAX);
__ addl(EAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, EBX, EDI, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, EBX, EDI, space);
// Initialize the tags.
// EAX: new object start as a tagged pointer.
@@ -803,8 +801,7 @@
__ MaybeTraceAllocation(kContextCid,
EAX,
&slow_case,
- Assembler::kFarJump,
- /* inline_isolate = */ false);
+ Assembler::kFarJump);
// Now allocate the object.
// EDX: number of context variables.
@@ -839,8 +836,7 @@
__ subl(EBX, EAX);
__ addl(EAX, Immediate(kHeapObjectTag));
// Generate isolate-independent code to allow sharing between isolates.
- __ UpdateAllocationStatsWithSize(cid, EBX, EDI, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, EBX, EDI, space);
// Calculate the size tag.
// EAX: new object.
@@ -1037,8 +1033,7 @@
__ j(ABOVE_EQUAL, &slow_case);
}
__ movl(Address(EDI, Heap::TopOffset(space)), EBX);
- __ UpdateAllocationStats(cls.id(), ECX, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStats(cls.id(), ECX, space);
// EAX: new object start (untagged).
// EBX: next object start.
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 7ae26bb..ce5db80 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -656,8 +656,7 @@
__ BranchUnsignedGreater(T3, Immediate(max_len), &slow_case);
const intptr_t cid = kArrayCid;
- __ MaybeTraceAllocation(kArrayCid, T4, &slow_case,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kArrayCid, T4, &slow_case);
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ LoadImmediate(T2, fixed_size);
@@ -691,8 +690,7 @@
// T3: heap.
__ sw(T1, Address(T3, Heap::TopOffset(space)));
__ addiu(T0, T0, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, T2, T4, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, T2, T4, space);
// Initialize the tags.
// T0: new object start as a tagged pointer.
@@ -937,8 +935,7 @@
__ LoadImmediate(T0, ~((kObjectAlignment) - 1));
__ and_(T2, T2, T0);
- __ MaybeTraceAllocation(kContextCid, T4, &slow_case,
- /* inline_isolate = */ false);
+ __ MaybeTraceAllocation(kContextCid, T4, &slow_case);
// Now allocate the object.
// T1: number of context variables.
// T2: object size.
@@ -971,8 +968,7 @@
// T5: heap.
__ sw(T3, Address(T5, Heap::TopOffset(space)));
__ addiu(V0, V0, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, T2, T5, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, T2, T5, space);
// Calculate the size tag.
// V0: new object.
@@ -1157,7 +1153,7 @@
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
__ sw(T3, Address(T5, Heap::TopOffset(space)));
- __ UpdateAllocationStats(cls.id(), T5, space, /* inline_isolate = */ false);
+ __ UpdateAllocationStats(cls.id(), T5, space);
// T2: new object start.
// T3: next object start.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index db210a1..4e8f0e0 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -590,8 +590,7 @@
// Check for allocation tracing.
__ MaybeTraceAllocation(kArrayCid,
&slow_case,
- Assembler::kFarJump,
- /* inline_isolate = */ false);
+ Assembler::kFarJump);
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ leaq(RDI, Address(RDI, TIMES_4, fixed_size)); // RDI is a Smi.
@@ -620,8 +619,7 @@
// next object start and initialize the object.
__ movq(Address(R13, Heap::TopOffset(space)), RCX);
__ addq(RAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, RDI, space,
- /* inline_isolate = */ false);
+ __ UpdateAllocationStatsWithSize(cid, RDI, space);
// Initialize the tags.
// RAX: new object start as a tagged pointer.
// RDI: allocation size.
@@ -847,8 +845,7 @@
// Check for allocation tracing.
__ MaybeTraceAllocation(kContextCid,
&slow_case,
- Assembler::kFarJump,
- /* inline_isolate = */ false);
+ Assembler::kFarJump);
// Now allocate the object.
// R10: number of context variables.
@@ -880,8 +877,7 @@
__ subq(R13, RAX);
__ addq(RAX, Immediate(kHeapObjectTag));
// Generate isolate-independent code to allow sharing between isolates.
- __ UpdateAllocationStatsWithSize(cid, R13, space,
- /* inline_isolate */ false);
+ __ UpdateAllocationStatsWithSize(cid, R13, space);
// Calculate the size tag.
// RAX: new object.
@@ -1072,7 +1068,7 @@
__ j(ABOVE_EQUAL, &slow_case);
}
__ movq(Address(RCX, Heap::TopOffset(space)), RBX);
- __ UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
+ __ UpdateAllocationStats(cls.id(), space);
// RAX: new object start (untagged).
// RBX: next object start.
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index 5fb54bc..04d6088 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -148,6 +148,7 @@
class SymbolTraits {
public:
static const char* Name() { return "SymbolTraits"; }
+ static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
const String& a_str = String::Cast(a);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index f20aa44..83c7458 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -352,7 +352,6 @@
V(_LocalTypeVariableMirror, "_LocalTypeVariableMirror") \
V(_SourceLocation, "_SourceLocation") \
V(hashCode, "get:hashCode") \
- V(_leftShiftWithMask32, "_leftShiftWithMask32") \
V(OptimizedOut, "<optimized out>") \
V(NotInitialized, "<not initialized>") \
V(AllocationStubFor, "[Stub] Allocate ") \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 5775145..3c7efee 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -318,6 +318,7 @@
void Thread::SetStackLimitFromStackBase(uword stack_base) {
// Set stack limit.
+#if !defined(TARGET_ARCH_DBC)
#if defined(USING_SIMULATOR)
// Ignore passed-in native stack top and use Simulator stack top.
Simulator* sim = Simulator::Current(); // May allocate a simulator.
@@ -326,6 +327,9 @@
// The overflow area is accounted for by the simulator.
#endif
SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize());
+#else
+ SetStackLimit(Simulator::Current()->StackTop());
+#endif // !defined(TARGET_ARCH_DBC)
}
@@ -348,11 +352,15 @@
/* static */
uword Thread::GetCurrentStackPointer() {
+#if !defined(TARGET_ARCH_DBC)
// Since AddressSanitizer's detect_stack_use_after_return instruments the
// C++ code to give out fake stack addresses, we call a stub in that case.
ASSERT(StubCode::GetStackPointer_entry() != NULL);
uword (*func)() = reinterpret_cast<uword (*)()>(
StubCode::GetStackPointer_entry()->EntryPoint());
+#else
+ uword (*func)() = NULL;
+#endif
// But for performance (and to support simulators), we normally use a local.
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
@@ -390,7 +398,7 @@
}
if (stack_limit_ == saved_stack_limit_) {
- stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
+ stack_limit_ = kInterruptStackLimit & ~kInterruptsMask;
}
stack_limit_ |= interrupt_bits;
}
@@ -437,7 +445,7 @@
deferred_interrupts_mask_ = 0;
if (deferred_interrupts_ != 0) {
if (stack_limit_ == saved_stack_limit_) {
- stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
+ stack_limit_ = kInterruptStackLimit & ~kInterruptsMask;
}
stack_limit_ |= deferred_interrupts_;
deferred_interrupts_ = 0;
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 8e126f5..4a21cc5 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -70,11 +70,10 @@
V(TypeParameter) \
-// 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) \
+#if defined(TARGET_ARCH_DBC)
+#define CACHED_VM_STUBS_LIST(V)
+#else
+#define CACHED_VM_STUBS_LIST(V) \
V(RawCode*, update_store_buffer_code_, \
StubCode::UpdateStoreBuffer_entry()->code(), NULL) \
V(RawCode*, fix_callers_target_code_, \
@@ -86,11 +85,28 @@
V(RawCode*, call_to_runtime_stub_, \
StubCode::CallToRuntime_entry()->code(), NULL) \
-#define CACHED_ADDRESSES_LIST(V) \
+#endif
+
+// 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) \
+ CACHED_VM_STUBS_LIST(V) \
+
+#if defined(TARGET_ARCH_DBC)
+#define CACHED_VM_STUBS_ADDRESSES_LIST(V)
+#else
+#define CACHED_VM_STUBS_ADDRESSES_LIST(V) \
V(uword, update_store_buffer_entry_point_, \
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0) \
V(uword, call_to_runtime_entry_point_, \
StubCode::CallToRuntime_entry()->EntryPoint(), 0) \
+
+#endif
+
+#define CACHED_ADDRESSES_LIST(V) \
+ CACHED_VM_STUBS_ADDRESSES_LIST(V) \
V(uword, native_call_wrapper_entry_point_, \
NativeEntry::NativeCallWrapperEntry(), 0) \
V(RawString**, predefined_symbols_address_, \
@@ -175,6 +191,13 @@
// The true stack limit for this isolate.
uword saved_stack_limit() const { return saved_stack_limit_; }
+#if defined(TARGET_ARCH_DBC)
+ // Access to the current stack limit for DBC interpreter.
+ uword stack_limit() const {
+ return stack_limit_;
+ }
+#endif
+
// Stack overflow flags
enum {
kOsrRequest = 0x1, // Current stack overflow caused by OSR request.
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 68e0784..0adf841 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -33,6 +33,9 @@
"Comma separated list of timeline streams to record. "
"Valid values: all, API, Compiler, Dart, Debugger, Embedder, "
"GC, Isolate, and VM.");
+DEFINE_FLAG(charp, timeline_recorder, "ring",
+ "Select the timeline recorder used. "
+ "Valid values: ring, endless, and startup.")
// Implementation notes:
//
@@ -77,6 +80,42 @@
//
+static TimelineEventRecorder* CreateTimelineRecorder() {
+ // Some flags require that we use the endless recorder.
+ const bool use_endless_recorder =
+ (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline;
+
+ const bool use_startup_recorder = FLAG_startup_timeline;
+
+ const char* flag = FLAG_timeline_recorder;
+
+ if (use_endless_recorder || (flag != NULL)) {
+ if (use_endless_recorder || (strcmp("endless", flag) == 0)) {
+ if (FLAG_trace_timeline) {
+ THR_Print("Using the endless timeline recorder.\n");
+ }
+ return new TimelineEventEndlessRecorder();
+ }
+ }
+
+ if (use_startup_recorder || (flag != NULL)) {
+ if (use_startup_recorder || (strcmp("startup", flag) == 0)) {
+ if (FLAG_trace_timeline) {
+ THR_Print("Using the startup recorder.\n");
+ }
+ return new TimelineEventStartupRecorder();
+ }
+ }
+
+ if (FLAG_trace_timeline) {
+ THR_Print("Using the ring timeline recorder.\n");
+ }
+
+ // Always fall back to the ring recorder.
+ return new TimelineEventRingRecorder();
+}
+
+
// Returns a caller freed array of stream names in FLAG_timeline_streams.
static MallocGrowableArray<char*>* GetEnabledByDefaultTimelineStreams() {
MallocGrowableArray<char*>* result = new MallocGrowableArray<char*>();
@@ -129,18 +168,8 @@
void Timeline::InitOnce() {
ASSERT(recorder_ == NULL);
- // Default to ring recorder being enabled.
- const bool use_ring_recorder = true;
- // Some flags require that we use the endless recorder.
- const bool use_endless_recorder =
- (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline;
- if (use_endless_recorder) {
- recorder_ = new TimelineEventEndlessRecorder();
- } else if (FLAG_startup_timeline) {
- recorder_ = new TimelineEventStartupRecorder();
- } else if (use_ring_recorder) {
- recorder_ = new TimelineEventRingRecorder();
- }
+ recorder_ = CreateTimelineRecorder();
+ ASSERT(recorder_ != NULL);
enabled_streams_ = GetEnabledByDefaultTimelineStreams();
// Global overrides.
#define TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \
@@ -295,6 +324,9 @@
void TimelineEvent::Reset() {
+ if (owns_label() && label_ != NULL) {
+ free(const_cast<char*>(label_));
+ }
state_ = 0;
thread_ = OSThread::kInvalidThreadId;
isolate_id_ = ILLEGAL_PORT;
@@ -303,6 +335,7 @@
FreeArguments();
set_pre_serialized_json(false);
set_event_type(kNone);
+ set_owns_label(false);
}
@@ -502,6 +535,7 @@
FreeArguments();
set_pre_serialized_json(false);
set_event_type(event_type);
+ set_owns_label(false);
}
@@ -1035,8 +1069,6 @@
if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
return;
}
- Thread* T = Thread::Current();
- StackZone zone(T);
Timeline::ReclaimCachedBlocksFromThreads();
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 9196ee0..f78b516 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -286,6 +286,10 @@
const char* GetSerializedJSON() const;
+ void set_owns_label(bool owns_label) {
+ state_ = OwnsLabelBit::update(owns_label, state_);
+ }
+
private:
void FreeArguments();
@@ -315,15 +319,21 @@
state_ = PreSerializedJSON::update(pre_serialized_json, state_);
}
+ bool owns_label() const {
+ return OwnsLabelBit::decode(state_);
+ }
+
enum StateBits {
kEventTypeBit = 0, // reserve 4 bits for type.
kPreSerializedJSON = 4,
- kNextBit = 5,
+ kOwnsLabelBit = 5,
+ kNextBit = 6,
};
class EventTypeField : public BitField<uword, EventType, kEventTypeBit, 4> {};
class PreSerializedJSON :
public BitField<uword, bool, kPreSerializedJSON, 1> {};
+ class OwnsLabelBit : public BitField<uword, bool, kOwnsLabelBit, 1> {};
int64_t timestamp0_;
int64_t timestamp1_;
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index defaea6..f170ffc 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -374,7 +374,7 @@
// using the ABI calling convention.
// ResultType is the return type of the assembler test function.
// ArgNType is the type of the Nth argument.
-#if defined(USING_SIMULATOR)
+#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
#if defined(ARCH_IS_64_BIT)
// TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
@@ -454,7 +454,7 @@
typedef ResultType (*FunctionType) (Arg1Type, Arg2Type, Arg3Type);
return reinterpret_cast<FunctionType>(entry())(arg1, arg2, arg3);
}
-#endif // USING_SIMULATOR
+#endif // defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
// Assemble test and set code_.
void Assemble();
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index f73d16d..fa053a3 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -19,6 +19,8 @@
'assembler_arm64.cc',
'assembler_arm64.h',
'assembler_arm64_test.cc',
+ 'assembler_dbc.cc',
+ 'assembler_dbc.h',
'assembler_ia32.cc',
'assembler_ia32.h',
'assembler_ia32_test.cc',
@@ -89,6 +91,7 @@
'code_patcher_arm_test.cc',
'code_patcher_arm64.cc',
'code_patcher_arm64_test.cc',
+ 'code_patcher_dbc.cc',
'code_patcher_ia32.cc',
'code_patcher_ia32_test.cc',
'code_patcher_mips.cc',
@@ -110,6 +113,7 @@
'cpu.h',
'cpu_arm.cc',
'cpu_arm64.cc',
+ 'cpu_dbc.cc',
'cpu_ia32.cc',
'cpu_mips.cc',
'cpu_test.cc',
@@ -140,6 +144,7 @@
'debugger_api_impl_test.cc',
'debugger_arm.cc',
'debugger_arm64.cc',
+ 'debugger_dbc.cc',
'debugger_ia32.cc',
'debugger_mips.cc',
'debugger_x64.cc',
@@ -151,6 +156,7 @@
'disassembler.h',
'disassembler_arm.cc',
'disassembler_arm64.cc',
+ 'disassembler_dbc.cc',
'disassembler_ia32.cc',
'disassembler_mips.cc',
'disassembler_test.cc',
@@ -177,6 +183,7 @@
'flow_graph_compiler.h',
'flow_graph_compiler_arm.cc',
'flow_graph_compiler_arm64.cc',
+ 'flow_graph_compiler_dbc.cc',
'flow_graph_compiler_ia32.cc',
'flow_graph_compiler_mips.cc',
'flow_graph_compiler_x64.cc',
@@ -218,6 +225,8 @@
'instructions_arm64.cc',
'instructions_arm64.h',
'instructions_arm64_test.cc',
+ 'instructions_dbc.cc',
+ 'instructions_dbc.h',
'instructions_ia32.cc',
'instructions_ia32.h',
'instructions_ia32_test.cc',
@@ -231,6 +240,7 @@
'intermediate_language.h',
'intermediate_language_arm.cc',
'intermediate_language_arm64.cc',
+ 'intermediate_language_dbc.cc',
'intermediate_language_ia32.cc',
'intermediate_language_mips.cc',
'intermediate_language_test.cc',
@@ -239,6 +249,7 @@
'intrinsifier.h',
'intrinsifier_arm.cc',
'intrinsifier_arm64.cc',
+ 'intrinsifier_dbc.cc',
'intrinsifier_ia32.cc',
'intrinsifier_mips.cc',
'intrinsifier_x64.cc',
@@ -377,6 +388,7 @@
'runtime_entry_list.h',
'runtime_entry_arm.cc',
'runtime_entry_arm64.cc',
+ 'runtime_entry_dbc.cc',
'runtime_entry_ia32.cc',
'runtime_entry_mips.cc',
'runtime_entry.cc',
@@ -410,6 +422,8 @@
'simulator_arm.h',
'simulator_arm64.cc',
'simulator_arm64.h',
+ 'simulator_dbc.cc',
+ 'simulator_dbc.h',
'simulator_mips.cc',
'simulator_mips.h',
'snapshot.cc',
@@ -436,6 +450,7 @@
'stub_code_arm_test.cc',
'stub_code_arm64.cc',
'stub_code_arm64_test.cc',
+ 'stub_code_dbc.cc',
'stub_code_ia32.cc',
'stub_code_ia32_test.cc',
'stub_code_mips.cc',
diff --git a/sdk/lib/_blink/dartium/_blink_dartium.dart b/sdk/lib/_blink/dartium/_blink_dartium.dart
index c0674f6..bb80827 100644
--- a/sdk/lib/_blink/dartium/_blink_dartium.dart
+++ b/sdk/lib/_blink/dartium/_blink_dartium.dart
@@ -347,7 +347,6 @@
if (s == "MimeTypeArray") return BlinkMimeTypeArray.instance;
if (s == "MouseEvent") return BlinkMouseEvent.instance;
if (s == "MutationCallback") return BlinkMutationCallback.instance;
- if (s == "MutationEvent") return BlinkMutationEvent.instance;
if (s == "MutationObserver") return BlinkMutationObserver.instance;
if (s == "MutationRecord") return BlinkMutationRecord.instance;
if (s == "NamedNodeMap") return BlinkNamedNodeMap.instance;
@@ -10946,27 +10945,6 @@
}
-class BlinkMutationEvent extends BlinkEvent {
- static final instance = new BlinkMutationEvent();
-
- attrChange_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis /* MutationEvent */, "attrChange");
-
- attrName_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis /* MutationEvent */, "attrName");
-
- newValue_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis /* MutationEvent */, "newValue");
-
- prevValue_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis /* MutationEvent */, "prevValue");
-
- relatedNode_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis /* MutationEvent */, "relatedNode");
-
- initMutationEvent_Callback_6_(mthis, __arg_0, __arg_1, __arg_2, __arg_3, __arg_4, __arg_5) => Blink_JsNative_DomException.callMethod(mthis /* MutationEvent */, "initMutationEvent", [__arg_0, __arg_1, __arg_2, __arg_3, __arg_4, __arg_5]);
-
- initMutationEvent_Callback_7_(mthis, __arg_0, __arg_1, __arg_2, __arg_3, __arg_4, __arg_5, __arg_6) => Blink_JsNative_DomException.callMethod(mthis /* MutationEvent */, "initMutationEvent", [__arg_0, __arg_1, __arg_2, __arg_3, __arg_4, __arg_5, __arg_6]);
-
- initMutationEvent_Callback_8_(mthis, __arg_0, __arg_1, __arg_2, __arg_3, __arg_4, __arg_5, __arg_6, __arg_7) => Blink_JsNative_DomException.callMethod(mthis /* MutationEvent */, "initMutationEvent", [__arg_0, __arg_1, __arg_2, __arg_3, __arg_4, __arg_5, __arg_6, __arg_7]);
-
-}
-
class BlinkMutationObserver {
static final instance = new BlinkMutationObserver();
diff --git a/sdk/lib/_internal/js_runtime/lib/async_patch.dart b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
index 20cd748..db2a4e1 100644
--- a/sdk/lib/_internal/js_runtime/lib/async_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
@@ -417,14 +417,14 @@
final value;
final int state;
- _IterationMarker._(this.state, this.value);
+ const _IterationMarker._(this.state, this.value);
static yieldStar(dynamic /* Iterable or Stream */ values) {
return new _IterationMarker._(YIELD_STAR, values);
}
static endOfIteration() {
- return new _IterationMarker._(ITERATION_ENDED, null);
+ return const _IterationMarker._(ITERATION_ENDED, null);
}
static yieldSingle(dynamic value) {
@@ -439,17 +439,33 @@
}
class _SyncStarIterator implements Iterator {
- final dynamic _body;
+ // _SyncStarIterator handles stepping a sync* generator body state machine.
+ //
+ // It also handles the stepping over 'nested' iterators to flatten yield*
+ // statements. For non-sync* iterators, [_nestedIterator] contains the
+ // iterator. We delegate to [_nestedIterator] when it is not `null`.
+ //
+ // For nested sync* iterators, [this] iterator acts on behalf of the innermost
+ // nested sync* iterator. The current state machine is suspended on a stack
+ // until the inner state machine ends.
- // If [runningNested] this is the nested iterator, otherwise it is the
- // current value.
+ // The state machine for the innermost _SyncStarIterator.
+ dynamic _body;
+
+ // The current value, unless iterating a non-sync* nested iterator.
dynamic _current = null;
- bool _runningNested = false;
- get current => _runningNested ? _current.current : _current;
+ // This is the nested iterator when iterating a yield* of a non-sync iterator.
+ Iterator _nestedIterator = null;
+
+ // Stack of suspended state machines when iterating a yield* of a sync*
+ // iterator.
+ List _suspendedBodies = null;
_SyncStarIterator(this._body);
+ get current => _nestedIterator == null ? _current : _nestedIterator.current;
+
_runBody() {
// TODO(sra): Find a way to hard-wire SUCCESS and ERROR codes.
return JS('',
@@ -472,33 +488,56 @@
_body, async_error_codes.SUCCESS, async_error_codes.ERROR);
}
-
bool moveNext() {
- if (_runningNested) {
- if (_current.moveNext()) {
+ while (true) {
+ if (_nestedIterator != null) {
+ if (_nestedIterator.moveNext()) {
+ return true;
+ } else {
+ _nestedIterator = null;
+ }
+ }
+ var value = _runBody();
+ if (value is _IterationMarker) {
+ int state = value.state;
+ if (state == _IterationMarker.ITERATION_ENDED) {
+ if (_suspendedBodies == null || _suspendedBodies.isEmpty) {
+ _current = null;
+ // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
+ return false;
+ }
+ // Resume the innermost suspended iterator.
+ _body = _suspendedBodies.removeLast();
+ continue;
+ } else if (state == _IterationMarker.UNCAUGHT_ERROR) {
+ // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
+ // This is a wrapped exception, so we use JavaScript throw to throw
+ // it.
+ JS('', 'throw #', value.value);
+ } else {
+ assert(state == _IterationMarker.YIELD_STAR);
+ Iterator inner = value.value.iterator;
+ if (inner is _SyncStarIterator) {
+ // Suspend the current state machine and start acting on behalf of
+ // the nested state machine.
+ //
+ // TODO(sra): Recognize "tail yield*" statements and avoid
+ // suspending the current body when all it will do is step without
+ // effect to ITERATION_ENDED.
+ (_suspendedBodies ??= []).add(_body);
+ _body = inner._body;
+ continue;
+ } else {
+ _nestedIterator = inner;
+ continue;
+ }
+ }
+ } else {
+ _current = value;
return true;
- } else {
- _runningNested = false;
}
}
- _current = _runBody();
- if (_current is _IterationMarker) {
- if (_current.state == _IterationMarker.ITERATION_ENDED) {
- _current = null;
- // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
- return false;
- } else if (_current.state == _IterationMarker.UNCAUGHT_ERROR) {
- // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
- // This is a wrapped exception, so we use JavaScript throw to throw it.
- JS('', 'throw #', _current.value);
- } else {
- assert(_current.state == _IterationMarker.YIELD_STAR);
- _current = _current.value.iterator;
- _runningNested = true;
- return moveNext();
- }
- }
- return true;
+ return false; // TODO(sra): Fix type inference so that this is not needed.
}
}
diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
index e403844..4487e15 100644
--- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
@@ -45,6 +45,14 @@
}
@patch
+class _AsyncDirectoryListerOps {
+ @patch
+ factory _AsyncDirectoryListerOps(int pointer) {
+ throw new UnsupportedError("Directory._list");
+ }
+}
+
+@patch
class _EventHandler {
@patch
static void _sendData(Object sender,
@@ -135,58 +143,10 @@
}
@patch
-class _RandomAccessFile {
+class _RandomAccessFileOps {
@patch
- static int _close(int id) {
- throw new UnsupportedError("RandomAccessFile._close");
- }
- @patch
- static int _getFD(int id) {
- throw new UnsupportedError("RandomAccessFile._getFD");
- }
- @patch
- static _readByte(int id) {
- throw new UnsupportedError("RandomAccessFile._readByte");
- }
- @patch
- static _read(int id, int bytes) {
- throw new UnsupportedError("RandomAccessFile._read");
- }
- @patch
- static _readInto(int id, List<int> buffer, int start, int end) {
- throw new UnsupportedError("RandomAccessFile._readInto");
- }
- @patch
- static _writeByte(int id, int value) {
- throw new UnsupportedError("RandomAccessFile._writeByte");
- }
- @patch
- static _writeFrom(int id, List<int> buffer, int start, int end) {
- throw new UnsupportedError("RandomAccessFile._writeFrom");
- }
- @patch
- static _position(int id) {
- throw new UnsupportedError("RandomAccessFile._position");
- }
- @patch
- static _setPosition(int id, int position) {
- throw new UnsupportedError("RandomAccessFile._setPosition");
- }
- @patch
- static _truncate(int id, int length) {
- throw new UnsupportedError("RandomAccessFile._truncate");
- }
- @patch
- static _length(int id) {
- throw new UnsupportedError("RandomAccessFile._length");
- }
- @patch
- static _flush(int id) {
- throw new UnsupportedError("RandomAccessFile._flush");
- }
- @patch
- static _lock(int id, int lock, int start, int end) {
- throw new UnsupportedError("RandomAccessFile._lock");
+ factory _RandomAccessFileOps(int pointer) {
+ throw new UnsupportedError("RandomAccessFile");
}
}
@@ -353,6 +313,10 @@
@patch
class NetworkInterface {
@patch
+ static bool get listSupported {
+ throw new UnsupportedError("NetworkInterface.listSupported");
+ }
+ @patch
static Future<List<NetworkInterface>> list({
bool includeLoopback: false,
bool includeLinkLocal: false,
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 87fc341..97b1244 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -259,8 +259,8 @@
* _outputSink.add(data);
* }
*
- * void addError(e, [st]) => _outputSink.addError(e, st);
- * void close() => _outputSink.close();
+ * void addError(e, [st]) { _outputSink.addError(e, st); }
+ * void close() { _outputSink.close(); }
* }
*
* class DuplicationTransformer implements StreamTransformer<String, String> {
diff --git a/sdk/lib/async/stream_transformers.dart b/sdk/lib/async/stream_transformers.dart
index ea4aaf7..979ce3a 100644
--- a/sdk/lib/async/stream_transformers.dart
+++ b/sdk/lib/async/stream_transformers.dart
@@ -213,10 +213,11 @@
_HandlerEventSink(this._handleData, this._handleError, this._handleDone,
this._sink);
- void add(S data) => _handleData(data, _sink);
- void addError(Object error, [StackTrace stackTrace])
- => _handleError(error, stackTrace, _sink);
- void close() => _handleDone(_sink);
+ void add(S data) { _handleData(data, _sink); }
+ void addError(Object error, [StackTrace stackTrace]) {
+ _handleError(error, stackTrace, _sink);
+ }
+ void close() { _handleDone(_sink); }
}
/**
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 5a22dc0..a5f31b6 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -93,7 +93,7 @@
* Effectively a shorthand for:
*
* new HashMap(equals: identical,
- * hashCode: identityHashCodeOf)
+ * hashCode: identityHashCode)
*/
external factory HashMap.identity();
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index bb76082..3ecb82c 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.dart
@@ -101,7 +101,7 @@
* Effectively a shorthand for:
*
* new HashSet<E>(equals: identical,
- * hashCode: identityHashCodeOf)
+ * hashCode: identityHashCode)
*/
external factory HashSet.identity();
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index e06f9e6..0f76652 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -80,7 +80,7 @@
* Effectively a shorthand for:
*
* new LinkedHashMap(equals: identical,
- * hashCode: identityHashCodeOf)
+ * hashCode: identityHashCode)
*/
external factory LinkedHashMap.identity();
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index a4848f4..a149692 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.dart
@@ -84,7 +84,7 @@
* Effectively a shorthand for:
*
* new LinkedHashSet(equals: identical,
- * hashCode: identityHashCodeOf)
+ * hashCode: identityHashCode)
*/
external factory LinkedHashSet.identity();
diff --git a/sdk/lib/convert/byte_conversion.dart b/sdk/lib/convert/byte_conversion.dart
index d27b40f..4c1ede4 100644
--- a/sdk/lib/convert/byte_conversion.dart
+++ b/sdk/lib/convert/byte_conversion.dart
@@ -64,8 +64,8 @@
_ByteAdapterSink(this._sink);
- void add(List<int> chunk) => _sink.add(chunk);
- void close() => _sink.close();
+ void add(List<int> chunk) { _sink.add(chunk); }
+ void close() { _sink.close(); }
}
/**
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index d450c75..a36c505 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.dart
@@ -130,11 +130,11 @@
: this._eventSink = sink,
_chunkedSink = converter.startChunkedConversion(sink);
- void add(S o) => _chunkedSink.add(o);
+ void add(S o) { _chunkedSink.add(o); }
void addError(Object error, [StackTrace stackTrace]) {
_eventSink.addError(error, stackTrace);
}
- void close() => _chunkedSink.close();
+ void close() { _chunkedSink.close(); }
}
/**
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index 2a0af75..7efe317 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -227,5 +227,5 @@
}
}
- void close() => _sink.close();
+ void close() { _sink.close(); }
}
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index 9c32673..bdfd39b 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.dart
@@ -93,13 +93,14 @@
_ClosableStringSink(this._sink, this._callback);
- void close() => _callback();
+ void close() { _callback(); }
- void writeCharCode(int charCode) => _sink.writeCharCode(charCode);
- void write(Object o) => _sink.write(o);
- void writeln([Object o = ""]) => _sink.writeln(o);
- void writeAll(Iterable objects, [String separator = ""])
- => _sink.writeAll(objects, separator);
+ void writeCharCode(int charCode) { _sink.writeCharCode(charCode); }
+ void write(Object o) { _sink.write(o); }
+ void writeln([Object o = ""]) { _sink.writeln(o); }
+ void writeAll(Iterable objects, [String separator = ""]) {
+ _sink.writeAll(objects, separator);
+ }
}
/**
@@ -177,7 +178,7 @@
void addSlice(String str, int start, int end, bool isLast);
void close();
- void add(String str) => addSlice(str, 0, str.length, false);
+ void add(String str) { addSlice(str, 0, str.length, false); }
ByteConversionSink asUtf8Sink(bool allowMalformed) {
return new _Utf8ConversionSink(this, allowMalformed);
@@ -207,7 +208,7 @@
if (isLast) close();
}
- void add(String str) => _stringSink.write(str);
+ void add(String str) { _stringSink.write(str); }
ByteConversionSink asUtf8Sink(bool allowMalformed) {
return new _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
@@ -253,7 +254,7 @@
_StringAdapterSink(this._sink);
- void add(String str) => _sink.add(str);
+ void add(String str) { _sink.add(str); }
void addSlice(String str, int start, int end, bool isLast) {
if (start == 0 && end == str.length) {
@@ -264,7 +265,7 @@
if (isLast) close();
}
- void close() => _sink.close();
+ void close() { _sink.close(); }
}
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index dd19502..4f45744 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -447,11 +447,11 @@
* Returns the first element.
*
* Throws a [StateError] if `this` is empty.
- * Otherwise returs the first element in the iteration order,
- * equivalent to `(iterator..moveNext())..current`.
+ * Otherwise returns the first element in the iteration order,
+ * equivalent to `this.elementAt(0)`.
*/
E get first {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
@@ -469,7 +469,7 @@
* without iterating through the previous ones).
*/
E get last {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
@@ -486,7 +486,7 @@
* Throws a [StateError] if `this` is empty or has more than one element.
*/
E get single {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) throw IterableElementError.noElement();
E result = it.current;
if (it.moveNext()) throw IterableElementError.tooMany();
@@ -610,9 +610,19 @@
final int _start;
final int _end;
final _Generator<E> _generator;
+
+ /// Creates an iterable that builds the elements from a generator function.
+ ///
+ /// The [generator] may be null, in which case the default generator
+ /// enumerating the integer positions is used. This means that [int] must
+ /// be assignable to [E] when no generator is provided. In practice this means
+ /// that the generator can only be emitted when [E] is equal to `dynamic`,
+ /// `int`, or `num`. The constructor will check that the types match.
_GeneratorIterable(this._end, E generator(int n))
: _start = 0,
- _generator = (generator != null) ? generator : _id;
+ // The `as` below is used as check to make sure that `int` is assignable
+ // to [E].
+ _generator = (generator != null) ? generator : _id as _Generator<E>;
_GeneratorIterable.slice(this._start, this._end, this._generator);
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index 38587b1..21f23ee 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.dart
@@ -439,14 +439,15 @@
static num parse(String input, [num onError(String input)]) {
String source = input.trim();
// TODO(lrn): Optimize to detect format and result type in one check.
- num result = int.parse(source, onError: _returnNull);
+ num result = int.parse(source, onError: _returnIntNull);
if (result != null) return result;
- result = double.parse(source, _returnNull);
+ result = double.parse(source, _returnDoubleNull);
if (result != null) return result;
if (onError == null) throw new FormatException(input);
return onError(input);
}
- /** Helper function for [parse]. */
- static _returnNull(_) => null;
+ /** Helper functions for [parse]. */
+ static int _returnIntNull(String _) => null;
+ static double _returnDoubleNull(String _) => null;
}
diff --git a/sdk/lib/core/symbol.dart b/sdk/lib/core/symbol.dart
index f60cdd1..44e9787 100644
--- a/sdk/lib/core/symbol.dart
+++ b/sdk/lib/core/symbol.dart
@@ -49,5 +49,5 @@
* Qualified member names, like `#foo.bar` are equal only if they have the
* same identifiers before the same final member name.
*/
- bool operator ==(Object other);
+ bool operator ==(other);
}
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index a1a5b5d..0cfeceb 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -148,7 +148,7 @@
* except for the unreserved characters, and replaces spaces with `+`.
* If `query` is the empty string, it is equivalent to omitting it.
* To have an actual empty query part,
- * use an empty list for `queryParameters`.
+ * use an empty map for `queryParameters`.
*
* If both `query` and `queryParameters` are omitted or `null`,
* the URI has no query part.
@@ -165,7 +165,7 @@
String path,
Iterable<String> pathSegments,
String query,
- Map<String, dynamic> queryParameters,
+ Map<String, dynamic/*String|Iterable<String>*/> queryParameters,
String fragment}) {
scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
@@ -1010,7 +1010,7 @@
String path,
Iterable<String> pathSegments,
String query,
- Map<String, String> queryParameters,
+ Map<String, dynamic/*String|Iterable<String>*/> queryParameters,
String fragment}) {
// Set to true if the scheme has (potentially) changed.
// In that case, the default port may also have changed and we need
@@ -1373,8 +1373,9 @@
return _removeDotSegments(path);
}
- static String _makeQuery(String query, int start, int end,
- Map<String, String> queryParameters) {
+ static String _makeQuery(
+ String query, int start, int end,
+ Map<String, dynamic/*String|Iterable<String>*/> queryParameters) {
if (query == null && queryParameters == null) return null;
if (query != null && queryParameters != null) {
throw new ArgumentError('Both query and queryParameters specified');
@@ -1469,7 +1470,7 @@
static String _escapeChar(int char) {
assert(char <= 0x10ffff); // It's a valid unicode code point.
- List codeUnits;
+ List<int> codeUnits;
if (char < 0x80) {
// ASCII, a single percent encoded sequence.
codeUnits = new List(3);
@@ -2365,8 +2366,7 @@
} else if (parts.length != 8) {
error('an address without a wildcard must contain exactly 8 parts');
}
- // TODO(ajohnsen): Consider using Uint8List.
- List bytes = new List<int>(16);
+ List<int> bytes = new Uint8List(16);
for (int i = 0, index = 0; i < parts.length; i++) {
int value = parts[i];
if (value == -1) {
@@ -2830,7 +2830,7 @@
Map<String, String> parameters,
bool base64: false}) {
StringBuffer buffer = new StringBuffer();
- List indices = [_noScheme];
+ List<int> indices = [_noScheme];
String charsetName;
String encodingName;
if (parameters != null) charsetName = parameters["charset"];
@@ -2867,7 +2867,7 @@
Map<String, String> parameters,
percentEncoded: false}) {
StringBuffer buffer = new StringBuffer();
- List indices = [_noScheme];
+ List<int> indices = [_noScheme];
_writeUri(mimeType, null, parameters, buffer, indices);
indices.add(buffer.length);
if (percentEncoded) {
@@ -3231,7 +3231,7 @@
const int slash = 0x2f;
const int semicolon = 0x3b;
const int equals = 0x3d;
- List indices = [start - 1];
+ List<int> indices = [start - 1];
int slashIndex = -1;
var char;
int i = start;
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index c463d8b..362832d 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -20,7 +20,7 @@
}
var block = new _SyncBlock._(name, _getTraceClock());
if (arguments is Map) {
- block.arguments.addAll(arguments);
+ block._appendArguments(arguments);
}
_stack.add(block);
}
@@ -108,7 +108,7 @@
}
var block = new _AsyncBlock._(name, _taskId);
if (arguments is Map) {
- block.arguments.addAll(arguments);
+ block._appendArguments(arguments);
}
_stack.add(block);
block._start();
@@ -171,7 +171,7 @@
final int _taskId;
/// An (optional) set of arguments which will be serialized to JSON and
/// associated with this block.
- final Map arguments = {};
+ Map _arguments;
_AsyncBlock._(this.name, this._taskId);
@@ -182,7 +182,7 @@
'b',
category,
name,
- _argumentsAsJson(arguments));
+ _argumentsAsJson(_arguments));
}
// Emit the finish event.
@@ -194,6 +194,13 @@
name,
_argumentsAsJson(null));
}
+
+ void _appendArguments(Map arguments) {
+ if (_arguments == null) {
+ _arguments = {};
+ }
+ _arguments.addAll(arguments);
+ }
}
/// A synchronous block of time on the timeline. This block should not be
@@ -205,7 +212,7 @@
final String name;
/// An (optional) set of arguments which will be serialized to JSON and
/// associated with this block.
- final Map arguments = {};
+ Map _arguments;
// The start time stamp.
final int _start;
@@ -220,7 +227,17 @@
_getTraceClock(),
category,
name,
- _argumentsAsJson(arguments));
+ _argumentsAsJson(_arguments));
+ }
+
+ void _appendArguments(Map arguments) {
+ if (arguments == null) {
+ return;
+ }
+ if (_arguments == null) {
+ _arguments = {};
+ }
+ _arguments.addAll(arguments);
}
}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 50e16be..4ca1158 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -143,12 +143,12 @@
*/
@DomName('AbstractWorker.errorEvent')
@DocsEditable()
- static const EventStreamProvider<ErrorEvent> errorEvent = const EventStreamProvider<ErrorEvent>('error');
+ static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
/// Stream of `error` events handled by this [AbstractWorker].
@DomName('AbstractWorker.onerror')
@DocsEditable()
- Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
+ Stream<Event> get onError => errorEvent.forTarget(this);
}
// 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
@@ -165,7 +165,7 @@
@DomName('HTMLAnchorElement.HTMLAnchorElement')
@DocsEditable()
factory AnchorElement({String href}) {
- var e = document.createElement("a");
+ AnchorElement e = document.createElement("a");
if (href != null) e.href = href;
return e;
}
@@ -1868,7 +1868,7 @@
@DomName('HTMLCanvasElement.HTMLCanvasElement')
@DocsEditable()
factory CanvasElement({int width, int height}) {
- var e = document.createElement("canvas");
+ CanvasElement e = document.createElement("canvas");
if (width != null) e.width = width;
if (height != null) e.height = height;
return e;
@@ -3099,7 +3099,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("CompositionEvent");
+ CompositionEvent e = document._createEvent("CompositionEvent");
if (Device.isFirefox) {
// Firefox requires the locale parameter that isn't supported elsewhere.
@@ -9429,7 +9429,7 @@
factory DeviceOrientationEvent(String type,
{bool canBubble: true, bool cancelable: true, num alpha: 0, num beta: 0,
num gamma: 0, bool absolute: false}) {
- var e = document._createEvent("DeviceOrientationEvent");
+ DeviceOrientationEvent e = document._createEvent("DeviceOrientationEvent");
e._initDeviceOrientationEvent(type, canBubble, cancelable, alpha, beta,
gamma, absolute);
return e;
@@ -9969,10 +9969,11 @@
@DocsEditable()
String _title;
+ @JSName('visibilityState')
@DomName('Document.visibilityState')
@DocsEditable()
@Experimental() // untriaged
- final String visibilityState;
+ final String _visibilityState;
@JSName('webkitFullscreenElement')
@DomName('Document.webkitFullscreenElement')
@@ -10605,9 +10606,8 @@
* For details about CSS selector syntax, see the
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
- ElementList<Element> querySelectorAll(String selectors) {
- return new _FrozenElementList._wrap(_querySelectorAll(selectors));
- }
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
/**
* Alias for [querySelector]. Note this function is deprecated because its
@@ -10625,7 +10625,7 @@
@deprecated
@Experimental()
@DomName('Document.querySelectorAll')
- ElementList<Element> queryAll(String relativeSelectors) =>
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
querySelectorAll(relativeSelectors);
/// Checks if [registerElement] is supported on the current platform.
@@ -10675,6 +10675,15 @@
[int whatToShow, NodeFilter filter])
=> JS('TreeWalker', '#.createTreeWalker(#, #, #, false)',
this, root, whatToShow, filter);
+
+ @DomName('Document.visibilityState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @Experimental()
+ String get visibilityState => JS('String',
+ '(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
+ '#.webkitVisibilityState)', this, this, this, this);
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -10717,7 +10726,7 @@
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -10734,8 +10743,9 @@
* For details about CSS selector syntax, see the
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
- ElementList<Element> querySelectorAll(String selectors) =>
- new _FrozenElementList._wrap(_querySelectorAll(selectors));
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
+
String get innerHtml {
final e = new Element.tag("div");
@@ -10792,9 +10802,8 @@
@deprecated
@Experimental()
@DomName('DocumentFragment.querySelectorAll')
- ElementList<Element> queryAll(String relativeSelectors) {
- return querySelectorAll(relativeSelectors);
- }
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
+ querySelectorAll(relativeSelectors);
// To suppress missing implicit constructor warnings.
factory DocumentFragment._() { throw new UnsupportedError("Not supported"); }
@@ -11202,125 +11211,53 @@
// To suppress missing implicit constructor warnings.
factory DomMatrixReadOnly._() { throw new UnsupportedError("Not supported"); }
- @DomName('DOMMatrixReadOnly.a')
- @DocsEditable()
- @Experimental() // untriaged
- final double a;
+ num get a => JS("num", "#.a", this);
- @DomName('DOMMatrixReadOnly.b')
- @DocsEditable()
- @Experimental() // untriaged
- final double b;
+ num get b => JS("num", "#.b", this);
- @DomName('DOMMatrixReadOnly.c')
- @DocsEditable()
- @Experimental() // untriaged
- final double c;
+ num get c => JS("num", "#.c", this);
- @DomName('DOMMatrixReadOnly.d')
- @DocsEditable()
- @Experimental() // untriaged
- final double d;
+ num get d => JS("num", "#.d", this);
- @DomName('DOMMatrixReadOnly.e')
- @DocsEditable()
- @Experimental() // untriaged
- final double e;
+ num get e => JS("num", "#.e", this);
- @DomName('DOMMatrixReadOnly.f')
- @DocsEditable()
- @Experimental() // untriaged
- final double f;
+ num get f => JS("num", "#.f", this);
- @DomName('DOMMatrixReadOnly.is2D')
- @DocsEditable()
- @Experimental() // untriaged
- final bool is2D;
+ bool get is2D => JS("bool", "#.is2D", this);
- @DomName('DOMMatrixReadOnly.isIdentity')
- @DocsEditable()
- @Experimental() // untriaged
- final bool isIdentity;
+ bool get isIdentity => JS("bool", "#.isIdentity", this);
- @DomName('DOMMatrixReadOnly.m11')
- @DocsEditable()
- @Experimental() // untriaged
- final double m11;
+ num get m11 => JS("num", "#.m11", this);
- @DomName('DOMMatrixReadOnly.m12')
- @DocsEditable()
- @Experimental() // untriaged
- final double m12;
+ num get m12 => JS("num", "#.m12", this);
- @DomName('DOMMatrixReadOnly.m13')
- @DocsEditable()
- @Experimental() // untriaged
- final double m13;
+ num get m13 => JS("num", "#.m13", this);
- @DomName('DOMMatrixReadOnly.m14')
- @DocsEditable()
- @Experimental() // untriaged
- final double m14;
+ num get m14 => JS("num", "#.m14", this);
- @DomName('DOMMatrixReadOnly.m21')
- @DocsEditable()
- @Experimental() // untriaged
- final double m21;
+ num get m21 => JS("num", "#.m21", this);
- @DomName('DOMMatrixReadOnly.m22')
- @DocsEditable()
- @Experimental() // untriaged
- final double m22;
+ num get m22 => JS("num", "#.m22", this);
- @DomName('DOMMatrixReadOnly.m23')
- @DocsEditable()
- @Experimental() // untriaged
- final double m23;
+ num get m23 => JS("num", "#.m23", this);
- @DomName('DOMMatrixReadOnly.m24')
- @DocsEditable()
- @Experimental() // untriaged
- final double m24;
+ num get m24 => JS("num", "#.m24", this);
- @DomName('DOMMatrixReadOnly.m31')
- @DocsEditable()
- @Experimental() // untriaged
- final double m31;
+ num get m31 => JS("num", "#.m31", this);
- @DomName('DOMMatrixReadOnly.m32')
- @DocsEditable()
- @Experimental() // untriaged
- final double m32;
+ num get m32 => JS("num", "#.m32", this);
- @DomName('DOMMatrixReadOnly.m33')
- @DocsEditable()
- @Experimental() // untriaged
- final double m33;
+ num get m33 => JS("num", "#.m33", this);
- @DomName('DOMMatrixReadOnly.m34')
- @DocsEditable()
- @Experimental() // untriaged
- final double m34;
+ num get m34 => JS("num", "#.m34", this);
- @DomName('DOMMatrixReadOnly.m41')
- @DocsEditable()
- @Experimental() // untriaged
- final double m41;
+ num get m41 => JS("num", "#.m41", this);
- @DomName('DOMMatrixReadOnly.m42')
- @DocsEditable()
- @Experimental() // untriaged
- final double m42;
+ num get m42 => JS("num", "#.m42", this);
- @DomName('DOMMatrixReadOnly.m43')
- @DocsEditable()
- @Experimental() // untriaged
- final double m43;
+ num get m43 => JS("num", "#.m43", this);
- @DomName('DOMMatrixReadOnly.m44')
- @DocsEditable()
- @Experimental() // untriaged
- final double m44;
+ num get m44 => JS("num", "#.m44", this);
@DomName('DOMMatrixReadOnly.multiply')
@DocsEditable()
@@ -11475,25 +11412,13 @@
}
static DomPointReadOnly _create_1(x, y, z, w) => JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#,#,#)', x, y, z, w);
- @DomName('DOMPointReadOnly.w')
- @DocsEditable()
- @Experimental() // untriaged
- final double w;
+ num get w => JS("num", "#.w", this);
- @DomName('DOMPointReadOnly.x')
- @DocsEditable()
- @Experimental() // untriaged
- final double x;
+ num get x => JS("num", "#.x", this);
- @DomName('DOMPointReadOnly.y')
- @DocsEditable()
- @Experimental() // untriaged
- final double y;
+ num get y => JS("num", "#.y", this);
- @DomName('DOMPointReadOnly.z')
- @DocsEditable()
- @Experimental() // untriaged
- final double z;
+ num get z => JS("num", "#.z", this);
}
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -11605,45 +11530,21 @@
}
static DomRectReadOnly _create_1(x, y, width, height) => JS('DomRectReadOnly', 'new DOMRectReadOnly(#,#,#,#)', x, y, width, height);
- @DomName('DOMRectReadOnly.bottom')
- @DocsEditable()
- @Experimental() // untriaged
- final double bottom;
+ num get bottom => JS("num", "#.bottom", this);
- @DomName('DOMRectReadOnly.height')
- @DocsEditable()
- @Experimental() // untriaged
- final double height;
+ num get height => JS("num", "#.height", this);
- @DomName('DOMRectReadOnly.left')
- @DocsEditable()
- @Experimental() // untriaged
- final double left;
+ num get left => JS("num", "#.left", this);
- @DomName('DOMRectReadOnly.right')
- @DocsEditable()
- @Experimental() // untriaged
- final double right;
+ num get right => JS("num", "#.right", this);
- @DomName('DOMRectReadOnly.top')
- @DocsEditable()
- @Experimental() // untriaged
- final double top;
+ num get top => JS("num", "#.top", this);
- @DomName('DOMRectReadOnly.width')
- @DocsEditable()
- @Experimental() // untriaged
- final double width;
+ num get width => JS("num", "#.width", this);
- @DomName('DOMRectReadOnly.x')
- @DocsEditable()
- @Experimental() // untriaged
- final double x;
+ num get x => JS("num", "#.x", this);
- @DomName('DOMRectReadOnly.y')
- @DocsEditable()
- @Experimental() // untriaged
- final double y;
+ num get y => JS("num", "#.y", this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -11727,10 +11628,6 @@
@Experimental() // untriaged
String __getter__(int index) native;
- @DomName('DOMStringList.contains')
- @DocsEditable()
- bool contains(String string) native;
-
@DomName('DOMStringList.item')
@DocsEditable()
String item(int index) native;
@@ -11877,7 +11774,7 @@
_filter(test, true);
}
- void _filter(bool test(var element), bool retainMatching) {
+ void _filter(bool test(Element element), bool retainMatching) {
var removed;
if (retainMatching) {
removed = _element.children.where((e) => !test(e));
@@ -12531,17 +12428,17 @@
// declared to return `ElementList`. This provides all the static analysis
// benefit so there is no need for this class have a constrained type parameter.
//
-class _FrozenElementList extends ListBase
- implements ElementList, NodeListWrapper {
+class _FrozenElementList<E extends Element> extends ListBase<E>
+ implements ElementList<E>, NodeListWrapper {
final List<Node> _nodeList;
_FrozenElementList._wrap(this._nodeList);
int get length => _nodeList.length;
- Element operator [](int index) => _nodeList[index];
+ E operator [](int index) => _downcast/*<Node, E>*/(_nodeList[index]);
- void operator []=(int index, Element value) {
+ void operator []=(int index, E value) {
throw new UnsupportedError('Cannot modify list');
}
@@ -12549,7 +12446,7 @@
throw new UnsupportedError('Cannot modify list');
}
- void sort([Comparator<Element> compare]) {
+ void sort([Comparator<E> compare]) {
throw new UnsupportedError('Cannot sort list');
}
@@ -12557,11 +12454,11 @@
throw new UnsupportedError('Cannot shuffle list');
}
- Element get first => _nodeList.first;
+ E get first => _downcast/*<Node, E>*/(_nodeList.first);
- Element get last => _nodeList.last;
+ E get last => _downcast/*<Node, E>*/(_nodeList.last);
- Element get single => _nodeList.single;
+ E get single => _downcast/*<Node, E>*/(_nodeList.single);
CssClassSet get classes => new _MultiElementCssClassSet(this);
@@ -12575,7 +12472,7 @@
//
// as the code below converts the Iterable[value] to a string multiple
// times. Maybe compute the string and set className here.
- _nodeList.forEach((e) => e.classes = value);
+ forEach((e) => e.classes = value);
}
CssRect get contentEdge => new _ContentCssListRect(this);
@@ -13315,7 +13212,7 @@
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -13333,8 +13230,8 @@
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
@DomName('Element.querySelectorAll')
- ElementList<Element> querySelectorAll(String selectors) =>
- new _FrozenElementList._wrap(_querySelectorAll(selectors));
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
/**
* Alias for [querySelector]. Note this function is deprecated because its
@@ -13352,7 +13249,7 @@
@deprecated
@DomName('Element.querySelectorAll')
@Experimental()
- ElementList<Element> queryAll(String relativeSelectors) =>
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
querySelectorAll(relativeSelectors);
/**
@@ -13550,14 +13447,13 @@
throw new ArgumentError("The frames parameter should be a List of Maps "
"with frame information");
}
- var convertedFrames = frames;
- if (convertedFrames is Iterable) {
+ var convertedFrames;
+ if (frames is Iterable) {
convertedFrames = frames.map(convertDartToNative_Dictionary).toList();
+ } else {
+ convertedFrames = frames;
}
- var convertedTiming = timing;
- if (convertedTiming is Map) {
- convertedTiming = convertDartToNative_Dictionary(convertedTiming);
- }
+ var convertedTiming = timing is Map ? convertDartToNative_Dictionary(timing) : timing;
return convertedTiming == null
? _animate(convertedFrames)
: _animate(convertedFrames, convertedTiming);
@@ -14025,7 +13921,7 @@
// Workaround for Safari bug. Was also previously Chrome bug 229142
// - URIs are not resolved in new doc.
- var base = _parseDocument.createElement('base');
+ BaseElement base = _parseDocument.createElement('base');
base.href = document.baseUri;
_parseDocument.head.append(base);
}
@@ -14940,9 +14836,8 @@
@DocsEditable()
bool hidden;
- @DomName('Element.isContentEditable')
- @DocsEditable()
- final bool isContentEditable;
+ // Using property as subclass shadows.
+ bool get isContentEditable => JS("bool", "#.isContentEditable", this);
@DomName('Element.lang')
@DocsEditable()
@@ -15067,10 +14962,8 @@
// Use implementation from Node.
// final String _namespaceUri;
- @JSName('outerHTML')
- @DomName('Element.outerHTML')
- @DocsEditable()
- final String outerHtml;
+ // Using property as subclass shadows.
+ String get outerHtml => JS("String", "#.outerHTML", this);
@JSName('scrollHeight')
@DomName('Element.scrollHeight')
@@ -16215,7 +16108,7 @@
e._initEvent(name, canBubble, cancelable);
return e;
}
-
+
/** The CSS selector involved with event delegation. */
String _selector;
@@ -16229,8 +16122,8 @@
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
' not arise as a result of event delegation.');
}
- var currentTarget = this.currentTarget;
- var target = this.target;
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
var matchedTarget;
do {
if (target.matches(_selector)) return target;
@@ -16523,26 +16416,24 @@
}
class ElementEvents extends Events {
- /* Raw event target. */
- final Element _ptr;
static final webkitEvents = {
- 'animationend' : 'webkitAnimationEnd',
- 'animationiteration' : 'webkitAnimationIteration',
- 'animationstart' : 'webkitAnimationStart',
- 'fullscreenchange' : 'webkitfullscreenchange',
+ 'animationend' : 'webkitAnimationEnd',
+ 'animationiteration' : 'webkitAnimationIteration',
+ 'animationstart' : 'webkitAnimationStart',
+ 'fullscreenchange' : 'webkitfullscreenchange',
'fullscreenerror' : 'webkitfullscreenerror',
- 'keyadded' : 'webkitkeyadded',
- 'keyerror' : 'webkitkeyerror',
- 'keymessage' : 'webkitkeymessage',
- 'needkey' : 'webkitneedkey',
- 'pointerlockchange' : 'webkitpointerlockchange',
- 'pointerlockerror' : 'webkitpointerlockerror',
- 'resourcetimingbufferfull' : 'webkitresourcetimingbufferfull',
+ 'keyadded' : 'webkitkeyadded',
+ 'keyerror' : 'webkitkeyerror',
+ 'keymessage' : 'webkitkeymessage',
+ 'needkey' : 'webkitneedkey',
+ 'pointerlockchange' : 'webkitpointerlockchange',
+ 'pointerlockerror' : 'webkitpointerlockerror',
+ 'resourcetimingbufferfull' : 'webkitresourcetimingbufferfull',
'transitionend': 'webkitTransitionEnd',
'speechchange' : 'webkitSpeechChange'
};
- ElementEvents(Element ptr) : this._ptr = ptr, super(ptr);
+ ElementEvents(Element ptr) : super(ptr);
Stream operator [](String type) {
if (webkitEvents.keys.contains(type.toLowerCase())) {
@@ -17980,7 +17871,10 @@
}
int watchId;
- var controller;
+ // TODO(jacobr): it seems like a bug that we have to specifiy the static
+ // type here for controller.stream to have the right type.
+ // dartbug.com/26278
+ StreamController<Geoposition> controller;
controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
@@ -19047,11 +18941,11 @@
@DomName('HTMLCollection.item')
@DocsEditable()
- Element item(int index) native;
+ Node item(int index) native;
@DomName('HTMLCollection.namedItem')
@DocsEditable()
- Element namedItem(String name) native;
+ Object namedItem(String name) native;
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -19171,61 +19065,6 @@
_webkitExitFullscreen();
}
- /**
- * Returns the element, if any, that is currently displayed in fullscreen.
- *
- * Returns null if there is currently no fullscreen element. You can use
- * this to determine if the page is in fullscreen mode.
- *
- * myVideo = new VideoElement();
- * if (document.fullscreenElement == null) {
- * myVideo.requestFullscreen();
- * print(document.fullscreenElement == myVideo); // true
- * }
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenElement')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- Element get fullscreenElement => _webkitFullscreenElement;
-
- /**
- * Returns true if this document can display elements in fullscreen mode.
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenEnabled')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get fullscreenEnabled => _webkitFullscreenEnabled;
-
- @DomName('Document.webkitHidden')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get hidden => _webkitHidden;
-
- @DomName('Document.visibilityState')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.FIREFOX)
- @SupportedBrowser(SupportedBrowser.IE, '10')
- @Experimental()
- String get visibilityState => JS('String',
- '(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
- '#.webkitVisibilityState)', this, this, this, this);
@Experimental()
/**
@@ -20394,7 +20233,7 @@
@DomName('HTMLImageElement.HTMLImageElement')
@DocsEditable()
factory ImageElement({String src, int width, int height}) {
- var e = document.createElement("img");
+ ImageElement e = document.createElement("img");
if (src != null) e.src = src;
if (width != null) e.width = width;
if (height != null) e.height = height;
@@ -20542,7 +20381,7 @@
ButtonInputElement {
factory InputElement({String type}) {
- var e = document.createElement("input");
+ InputElement e = document.createElement("input");
if (type != null) {
try {
// IE throws an exception for unknown types.
@@ -21402,15 +21241,15 @@
@Native("KeyboardEvent")
class KeyboardEvent extends UIEvent {
- /**
- * Programmatically create a KeyboardEvent.
+ /**
+ * Programmatically create a KeyboardEvent.
*
* Due to browser differences, keyCode, charCode, or keyIdentifier values
* cannot be specified in this base level constructor. This constructor
* enables the user to programmatically create and dispatch a [KeyboardEvent],
* but it will not contain any particular key content. For programmatically
* creating keyboard events with specific key value contents, see the custom
- * Event [KeyEvent].
+ * Event [KeyEvent].
*/
factory KeyboardEvent(String type,
{Window view, bool canBubble: true, bool cancelable: true,
@@ -21419,7 +21258,7 @@
if (view == null) {
view = window;
}
- final e = document._createEvent("KeyboardEvent");
+ KeyboardEvent e = document._createEvent("KeyboardEvent");
e._initKeyboardEvent(type, canBubble, cancelable, view, "",
keyLocation, ctrlKey, altKey, shiftKey, metaKey);
return e;
@@ -23438,7 +23277,7 @@
factory MessageEvent(String type,
{bool canBubble: false, bool cancelable: false, Object data,
String origin, String lastEventId,
- Window source, List messagePorts}) {
+ Window source, List<MessagePort> messagePorts}) {
if (source == null) {
source = window;
}
@@ -23448,7 +23287,7 @@
type, canBubble, cancelable, data, origin, lastEventId, source,
messagePorts);
}
- var event = document._createEvent("MessageEvent");
+ MessageEvent event = document._createEvent("MessageEvent");
event._initMessageEvent(type, canBubble, cancelable, data, origin,
lastEventId, source, messagePorts);
return event;
@@ -24066,7 +23905,7 @@
if (view == null) {
view = window;
}
- var event = document._createEvent('MouseEvent');
+ MouseEvent event = document._createEvent('MouseEvent');
event._initMouseEvent(type, canBubble, cancelable, view, detail,
screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
button, relatedTarget);
@@ -24210,22 +24049,6 @@
@deprecated
final Node toElement;
- @JSName('webkitMovementX')
- @DomName('MouseEvent.webkitMovementX')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- final int _webkitMovementX;
-
- @JSName('webkitMovementY')
- @DomName('MouseEvent.webkitMovementY')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- final int _webkitMovementY;
-
// Use implementation from UIEvent.
// final int _which;
@@ -24249,9 +24072,9 @@
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_webkitMovementX, _webkitMovementY);
+ Point get movement => new Point(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
@@ -25110,7 +24933,7 @@
set nodes(Iterable<Node> value) {
// Copy list first since we don't want liveness during iteration.
// TODO(jacobr): there is a better way to do this.
- List copy = new List.from(value);
+ var copy = value.toList();
text = '';
for (Node node in copy) {
append(node);
@@ -29444,8 +29267,7 @@
// Override default options, since IE returns SelectElement itself and it
// does not operate as a List.
List<OptionElement> get options {
- var options = this.querySelectorAll('option').where(
- (e) => e is OptionElement).toList();
+ var options = new List<OptionElement>.from(this.querySelectorAll('option'));
return new UnmodifiableListView(options);
}
@@ -31333,11 +31155,11 @@
}
// TODO(nweiz): update this when maps support lazy iteration
- bool containsValue(String value) => values.any((e) => e == value);
+ bool containsValue(Object value) => values.any((e) => e == value);
- bool containsKey(String key) => _getItem(key) != null;
+ bool containsKey(Object key) => _getItem(key) != null;
- String operator [](String key) => _getItem(key);
+ String operator [](Object key) => _getItem(key);
void operator []=(String key, String value) { _setItem(key, value); }
@@ -31346,7 +31168,7 @@
return this[key];
}
- String remove(String key) {
+ String remove(Object key) {
final value = this[key];
_removeItem(key);
return value;
@@ -31364,13 +31186,13 @@
}
Iterable<String> get keys {
- final keys = [];
+ final keys = <String>[];
forEach((k, v) => keys.add(k));
return keys;
}
Iterable<String> get values {
- final values = [];
+ final values = <String>[];
forEach((k, v) => values.add(v));
return values;
}
@@ -31452,7 +31274,7 @@
{bool canBubble: false, bool cancelable: false, String key, String oldValue,
String newValue, String url, Storage storageArea}) {
- var e = document._createEvent("StorageEvent");
+ StorageEvent e = document._createEvent("StorageEvent");
e._initStorageEvent(type, canBubble, cancelable, key, oldValue,
newValue, url, storageArea);
return e;
@@ -32386,7 +32208,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("TextEvent");
+ TextEvent e = document._createEvent("TextEvent");
e._initTextEvent(type, canBubble, cancelable, view, data);
return e;
}
@@ -32980,7 +32802,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("TouchEvent");
+ TouchEvent e = document._createEvent("TouchEvent");
e._initTouchEvent(touches, targetTouches, changedTouches, type, view,
screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey);
return e;
@@ -33414,7 +33236,7 @@
if (view == null) {
view = window;
}
- final e = document._createEvent("UIEvent");
+ UIEvent e = document._createEvent("UIEvent");
e._initUIEvent(type, canBubble, cancelable, view, detail);
return e;
}
@@ -34817,7 +34639,7 @@
@DomName('Window.requestAnimationFrame')
int requestAnimationFrame(FrameRequestCallback callback) {
_ensureRequestAnimationFrame();
- return _requestAnimationFrame(_wrapZone(callback));
+ return _requestAnimationFrame(_wrapZone/*<num, dynamic>*/(callback));
}
/**
@@ -36732,12 +36554,11 @@
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
var stream = new _EventStream(e, _eventType, useCapture);
- var controller = new StreamController(sync: true);
+ var controller = new StreamController<BeforeUnloadEvent>(sync: true);
stream.listen((event) {
var wrapped = new _BeforeUnloadEvent(event);
controller.add(wrapped);
- return wrapped.returnValue;
});
return controller.stream;
@@ -37552,13 +37373,6 @@
// Use implementation from Node.
// final String nodeValue;
- // Shadowing definition.
- String get text => JS("String", "#.textContent", this);
-
- set text(String value) {
- JS("void", "#.textContent = #", this, value);
- }
-
@DomName('Attr.value')
@DocsEditable()
String value;
@@ -38284,29 +38098,6 @@
// BSD-style license that can be found in the LICENSE file.
-@DomName('MutationEvent')
-// http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents
-@deprecated
-@Native("MutationEvent")
-abstract class _MutationEvent extends Event {
- factory _MutationEvent(String type,
- {bool canBubble: false, bool cancelable: false, Node relatedNode,
- String prevValue, String newValue, String attrName, int attrChange: 0}) {
-
- var event = document._createEvent('MutationEvent');
- event._initMutationEvent(type, canBubble, cancelable, relatedNode,
- prevValue, newValue, attrName, attrChange);
- return event;
- }
- // To suppress missing implicit constructor warnings.
- factory _MutationEvent._() { throw new UnsupportedError("Not supported"); }
-
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
@DocsEditable()
@DomName('NamedNodeMap')
// http://dom.spec.whatwg.org/#namednodemap
@@ -38784,7 +38575,7 @@
other.forEach((k, v) { this[k] = v; });
}
- bool containsValue(String value) {
+ bool containsValue(Object value) {
for (var v in this.values) {
if (value == v) {
return true;
@@ -38816,10 +38607,11 @@
Iterable<String> get keys {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var keys = new List<String>();
+ var keys = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- keys.add(attributes[i].name);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ keys.add(attr.name);
}
}
return keys;
@@ -38828,10 +38620,11 @@
Iterable<String> get values {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var values = new List<String>();
+ var values = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- values.add(attributes[i].value);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ values.add(attr.value);
}
}
return values;
@@ -38862,11 +38655,11 @@
_ElementAttributeMap(Element element): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttribute(key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttribute(key);
}
@@ -38874,7 +38667,7 @@
_element.setAttribute(key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = _element.getAttribute(key);
_element._removeAttribute(key);
return value;
@@ -38899,11 +38692,11 @@
_NamespacedAttributeMap(Element element, this._namespace): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttributeNS(_namespace, key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttributeNS(_namespace, key);
}
@@ -38911,7 +38704,7 @@
_element.setAttributeNS(_namespace, key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = this[key];
_element._removeAttributeNS(_namespace, key);
return value;
@@ -38945,11 +38738,11 @@
}
// TODO: Use lazy iterator when it is available on Map.
- bool containsValue(String value) => values.any((v) => v == value);
+ bool containsValue(Object value) => values.any((v) => v == value);
- bool containsKey(String key) => _attributes.containsKey(_attr(key));
+ bool containsKey(Object key) => _attributes.containsKey(_attr(key));
- String operator [](String key) => _attributes[_attr(key)];
+ String operator [](Object key) => _attributes[_attr(key)];
void operator []=(String key, String value) {
_attributes[_attr(key)] = value;
@@ -38958,7 +38751,7 @@
String putIfAbsent(String key, String ifAbsent()) =>
_attributes.putIfAbsent(_attr(key), ifAbsent);
- String remove(String key) => _attributes.remove(_attr(key));
+ String remove(Object key) => _attributes.remove(_attr(key));
void clear() {
// Needs to operate on a snapshot since we are mutating the collection.
@@ -38976,7 +38769,7 @@
}
Iterable<String> get keys {
- final keys = new List<String>();
+ final keys = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
keys.add(_strip(key));
@@ -38986,7 +38779,7 @@
}
Iterable<String> get values {
- final values = new List<String>();
+ final values = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
values.add(value);
@@ -39217,7 +39010,7 @@
* * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
* from WHATWG.
*/
- void postMessage(var message, String targetOrigin, [List messagePorts]);
+ void postMessage(var message, String targetOrigin, [List<MessagePort> messagePorts]);
}
abstract class LocationBase {
@@ -39271,7 +39064,7 @@
* [value] must be a valid 'token' representing a single class, i.e. a
* non-empty string containing no whitespace.
*/
- bool contains(String value);
+ bool contains(Object value);
/**
* Add the class [value] to element.
@@ -39323,7 +39116,7 @@
* Each element of [iterable] must be a valid 'token' representing a single
* class, i.e. a non-empty string containing no whitespace.
*/
- void removeAll(Iterable<String> iterable);
+ void removeAll(Iterable<Object> iterable);
/**
* Toggles all classes specified in [iterable] on element.
@@ -39351,7 +39144,7 @@
*/
class _ContentCssRect extends CssRect {
- _ContentCssRect(element) : super(element);
+ _ContentCssRect(Element element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
@@ -39372,9 +39165,11 @@
if (newHeight is Dimension) {
if (newHeight.value < 0) newHeight = new Dimension.px(0);
_element.style.height = newHeight.toString();
- } else {
+ } else if (newHeight is num) {
if (newHeight < 0) newHeight = 0;
_element.style.height = '${newHeight}px';
+ } else {
+ throw new ArgumentError("newHeight is not a Dimension or num");
}
}
@@ -39390,9 +39185,11 @@
if (newWidth is Dimension) {
if (newWidth.value < 0) newWidth = new Dimension.px(0);
_element.style.width = newWidth.toString();
- } else {
+ } else if (newWidth is num) {
if (newWidth < 0) newWidth = 0;
_element.style.width = '${newWidth}px';
+ } else {
+ throw new ArgumentError("newWidth is not a Dimension or num");
}
}
@@ -39409,7 +39206,7 @@
class _ContentCssListRect extends _ContentCssRect {
List<Element> _elementList;
- _ContentCssListRect(elementList) : super(elementList.first) {
+ _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
_elementList = elementList;
}
@@ -39498,10 +39295,10 @@
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
-abstract class CssRect extends MutableRectangle<num> {
+abstract class CssRect implements Rectangle<num> {
Element _element;
- CssRect(this._element) : super(0, 0, 0, 0);
+ CssRect(this._element);
num get left;
@@ -39594,6 +39391,102 @@
}
return val;
}
+
+ // TODO(jacobr): these methods are duplicated from _RectangleBase in dart:math
+ // Ideally we would provide a RectangleMixin class that provides this implementation.
+ // In an ideal world we would exp
+ /** The x-coordinate of the right edge. */
+ num get right => left + width;
+ /** The y-coordinate of the bottom edge. */
+ num get bottom => top + height;
+
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is !Rectangle) return false;
+ return left == other.left && top == other.top && right == other.right &&
+ bottom == other.bottom;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
+ right.hashCode, bottom.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
+ */
+ Rectangle<num> intersection(Rectangle<num> other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle<num>(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle<num> boundingBox(Rectangle<num> other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle<num>(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point<num> get topLeft => new Point<num>(this.left, this.top);
+ Point<num> get topRight => new Point<num>(this.left + this.width, this.top);
+ Point<num> get bottomRight => new Point<num>(this.left + this.width,
+ this.top + this.height);
+ Point<num> get bottomLeft => new Point<num>(this.left,
+ this.top + this.height);
}
final _HEIGHT = ['top', 'bottom'];
@@ -39722,11 +39615,11 @@
_addAll(_element, iterable);
}
- void removeAll(Iterable<String> iterable) {
+ void removeAll(Iterable<Object> iterable) {
_removeAll(_element, iterable);
}
- void retainAll(Iterable<String> iterable) {
+ void retainAll(Iterable<Object> iterable) {
_removeWhere(_element, iterable.toSet().contains, false);
}
@@ -39981,7 +39874,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
- new _EventStream(e, _eventType, useCapture);
+ new _EventStream<T>(e, _eventType, useCapture);
/**
* Gets an [ElementEventStream] for this event type, on the specified element.
@@ -40005,7 +39898,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -40076,8 +39969,8 @@
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
@@ -40091,6 +39984,11 @@
}
}
+bool _matchesWithAncestors(Event event, String selector) {
+ var target = event.target;
+ return target is Element ? target.matchesWithAncestors(selector) : false;
+}
+
/**
* Adapter for exposing DOM Element events as streams, while also allowing
* event delegation.
@@ -40101,7 +39999,7 @@
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -40125,7 +40023,7 @@
this._targetList, this._eventType, this._useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -40135,37 +40033,46 @@
{ Function onError,
void onDone(),
bool cancelOnError}) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, _useCapture));
+ pool.add(new _EventStream<T>(target, _eventType, _useCapture));
}
return pool.stream.listen(onData, onError: onError, onDone: onDone,
cancelOnError: cancelOnError);
}
StreamSubscription<T> capture(void onData(T event)) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, true));
+ pool.add(new _EventStream<T>(target, _eventType, true));
}
return pool.stream.listen(onData);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
}
+// We would like this to just be EventListener<T> but that typdef cannot
+// use generics until dartbug/26276 is fixed.
+typedef _EventListener<T extends Event>(T event);
+
class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
int _pauseCount = 0;
EventTarget _target;
final String _eventType;
- var _onData;
+ EventListener _onData;
final bool _useCapture;
- _EventStreamSubscription(this._target, this._eventType, onData,
- this._useCapture) : _onData = _wrapZone(onData) {
+ // TODO(jacobr): for full strong mode correctness we should write
+ // _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((e) => onData(e as T))
+ // but that breaks 114 co19 tests as well as multiple html tests as it is reasonable
+ // to pass the wrong type of event object to an event listener as part of a
+ // test.
+ _EventStreamSubscription(this._target, this._eventType, void onData(T event),
+ this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@@ -40187,8 +40094,7 @@
}
// Remove current event listener.
_unlisten();
-
- _onData = _wrapZone(handleData);
+ _onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@@ -40267,8 +40173,8 @@
onDone: onDone, cancelOnError: cancelOnError);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> _streamController.stream;
bool get isBroadcast => true;
@@ -40359,16 +40265,16 @@
const _CustomEventStreamProvider(this._eventTypeGetter);
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
- return new _EventStream(e, _eventTypeGetter(e), useCapture);
+ return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> _forElementList(ElementList e,
{bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
String getEventType(EventTarget target) {
@@ -41747,7 +41653,7 @@
* The set of keys that have been pressed down without seeing their
* corresponding keyup event.
*/
- final List<KeyboardEvent> _keyDownList = <KeyboardEvent>[];
+ final List<KeyEvent> _keyDownList = <KeyEvent>[];
/** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
final String _type;
@@ -41806,8 +41712,9 @@
* General constructor, performs basic initialization for our improved
* KeyboardEvent controller.
*/
- _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
+ _KeyboardEventHandler(this._type):
+ _stream = new _CustomKeyEventStreamImpl('event'), _target = null,
+ super(_EVENT_TYPE);
/**
* Hook up all event listeners under the covers so we can estimate keycodes
@@ -42115,7 +42022,6 @@
// BSD-style license that can be found in the LICENSE file.
-
/**
* Class which helps construct standard node validation policies.
*
@@ -42133,11 +42039,9 @@
* appropriate.
*/
class NodeValidatorBuilder implements NodeValidator {
-
final List<NodeValidator> _validators = <NodeValidator>[];
- NodeValidatorBuilder() {
- }
+ NodeValidatorBuilder() {}
/**
* Creates a new NodeValidatorBuilder which accepts common constructs.
@@ -42266,29 +42170,17 @@
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
+ var attrs = attributes
+ ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
if (uriPolicy == null) {
uriPolicy = new UriPolicy();
}
add(new _CustomElementNodeValidator(
- uriPolicy,
- [tagNameUpper],
- attrs,
- uriAttrs,
- false,
- true));
+ uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
}
/**
@@ -42303,37 +42195,26 @@
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var baseNameUpper = baseName.toUpperCase();
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
+ var attrs = attributes
+ ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
if (uriPolicy == null) {
uriPolicy = new UriPolicy();
}
- add(new _CustomElementNodeValidator(
- uriPolicy,
- [tagNameUpper, baseNameUpper],
- attrs,
- uriAttrs,
- true,
- false));
+ add(new _CustomElementNodeValidator(uriPolicy,
+ [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
}
- void allowElement(String tagName, {UriPolicy uriPolicy,
- Iterable<String> attributes,
- Iterable<String> uriAttributes}) {
-
- allowCustomElement(tagName, uriPolicy: uriPolicy,
+ void allowElement(String tagName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ allowCustomElement(tagName,
+ uriPolicy: uriPolicy,
attributes: attributes,
uriAttributes: uriAttributes);
}
@@ -42364,8 +42245,8 @@
}
bool allowsAttribute(Element element, String attributeName, String value) {
- return _validators.any(
- (v) => v.allowsAttribute(element, attributeName, value));
+ return _validators
+ .any((v) => v.allowsAttribute(element, attributeName, value));
}
}
@@ -42376,76 +42257,70 @@
final UriPolicy uriPolicy;
factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
- return new _SimpleNodeValidator(uriPolicy,
- allowedElements: const [
- 'A',
- 'FORM'],
- allowedAttributes: const [
- 'A::accesskey',
- 'A::coords',
- 'A::hreflang',
- 'A::name',
- 'A::shape',
- 'A::tabindex',
- 'A::target',
- 'A::type',
- 'FORM::accept',
- 'FORM::autocomplete',
- 'FORM::enctype',
- 'FORM::method',
- 'FORM::name',
- 'FORM::novalidate',
- 'FORM::target',
- ],
- allowedUriAttributes: const [
- 'A::href',
- 'FORM::action',
- ]);
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'A',
+ 'FORM'
+ ], allowedAttributes: const [
+ 'A::accesskey',
+ 'A::coords',
+ 'A::hreflang',
+ 'A::name',
+ 'A::shape',
+ 'A::tabindex',
+ 'A::target',
+ 'A::type',
+ 'FORM::accept',
+ 'FORM::autocomplete',
+ 'FORM::enctype',
+ 'FORM::method',
+ 'FORM::name',
+ 'FORM::novalidate',
+ 'FORM::target',
+ ], allowedUriAttributes: const [
+ 'A::href',
+ 'FORM::action',
+ ]);
}
factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
- return new _SimpleNodeValidator(uriPolicy,
- allowedElements: const [
- 'IMG'
- ],
- allowedAttributes: const [
- 'IMG::align',
- 'IMG::alt',
- 'IMG::border',
- 'IMG::height',
- 'IMG::hspace',
- 'IMG::ismap',
- 'IMG::name',
- 'IMG::usemap',
- 'IMG::vspace',
- 'IMG::width',
- ],
- allowedUriAttributes: const [
- 'IMG::src',
- ]);
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'IMG'
+ ], allowedAttributes: const [
+ 'IMG::align',
+ 'IMG::alt',
+ 'IMG::border',
+ 'IMG::height',
+ 'IMG::hspace',
+ 'IMG::ismap',
+ 'IMG::name',
+ 'IMG::usemap',
+ 'IMG::vspace',
+ 'IMG::width',
+ ], allowedUriAttributes: const [
+ 'IMG::src',
+ ]);
}
factory _SimpleNodeValidator.allowTextElements() {
- return new _SimpleNodeValidator(null,
- allowedElements: const [
- 'B',
- 'BLOCKQUOTE',
- 'BR',
- 'EM',
- 'H1',
- 'H2',
- 'H3',
- 'H4',
- 'H5',
- 'H6',
- 'HR',
- 'I',
- 'LI',
- 'OL',
- 'P',
- 'SPAN',
- 'UL',
- ]);
+ return new _SimpleNodeValidator(null, allowedElements: const [
+ 'B',
+ 'BLOCKQUOTE',
+ 'BR',
+ 'EM',
+ 'H1',
+ 'H2',
+ 'H3',
+ 'H4',
+ 'H5',
+ 'H6',
+ 'HR',
+ 'I',
+ 'LI',
+ 'OL',
+ 'P',
+ 'SPAN',
+ 'UL',
+ ]);
}
/**
@@ -42454,15 +42329,16 @@
* lowercase attribute name. For example `'IMG:src'`.
*/
_SimpleNodeValidator(this.uriPolicy,
- {Iterable<String> allowedElements, Iterable<String> allowedAttributes,
- Iterable<String> allowedUriAttributes}) {
+ {Iterable<String> allowedElements,
+ Iterable<String> allowedAttributes,
+ Iterable<String> allowedUriAttributes}) {
this.allowedElements.addAll(allowedElements ?? const []);
allowedAttributes = allowedAttributes ?? const [];
allowedUriAttributes = allowedUriAttributes ?? const [];
- var legalAttributes = allowedAttributes.where(
- (x) => !_Html5NodeValidator._uriAttributes.contains(x));
- var extraUriAttributes = allowedAttributes.where(
- (x) => _Html5NodeValidator._uriAttributes.contains(x));
+ var legalAttributes = allowedAttributes
+ .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
+ var extraUriAttributes = allowedAttributes
+ .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
this.allowedAttributes.addAll(legalAttributes);
this.allowedUriAttributes.addAll(allowedUriAttributes);
this.allowedUriAttributes.addAll(extraUriAttributes);
@@ -42495,19 +42371,19 @@
final bool allowTypeExtension;
final bool allowCustomTag;
- _CustomElementNodeValidator(UriPolicy uriPolicy,
+ _CustomElementNodeValidator(
+ UriPolicy uriPolicy,
Iterable<String> allowedElements,
Iterable<String> allowedAttributes,
Iterable<String> allowedUriAttributes,
bool allowTypeExtension,
- bool allowCustomTag):
-
- super(uriPolicy,
- allowedElements: allowedElements,
- allowedAttributes: allowedAttributes,
- allowedUriAttributes: allowedUriAttributes),
- this.allowTypeExtension = allowTypeExtension == true,
- this.allowCustomTag = allowCustomTag == true;
+ bool allowCustomTag)
+ : this.allowTypeExtension = allowTypeExtension == true,
+ this.allowCustomTag = allowCustomTag == true,
+ super(uriPolicy,
+ allowedElements: allowedElements,
+ allowedAttributes: allowedAttributes,
+ allowedUriAttributes: allowedUriAttributes);
bool allowsElement(Element element) {
if (allowTypeExtension) {
@@ -42517,12 +42393,14 @@
allowedElements.contains(Element._safeTagName(element));
}
}
- return allowCustomTag && allowedElements.contains(Element._safeTagName(element));
+ return allowCustomTag &&
+ allowedElements.contains(Element._safeTagName(element));
}
bool allowsAttribute(Element element, String attributeName, String value) {
- if (allowsElement(element)) {
- if (allowTypeExtension && attributeName == 'is' &&
+ if (allowsElement(element)) {
+ if (allowTypeExtension &&
+ attributeName == 'is' &&
allowedElements.contains(value.toUpperCase())) {
return true;
}
@@ -42533,19 +42411,22 @@
}
class _TemplatingNodeValidator extends _SimpleNodeValidator {
- static const _TEMPLATE_ATTRS =
- const <String>['bind', 'if', 'ref', 'repeat', 'syntax'];
+ static const _TEMPLATE_ATTRS = const <String>[
+ 'bind',
+ 'if',
+ 'ref',
+ 'repeat',
+ 'syntax'
+ ];
final Set<String> _templateAttrs;
- _TemplatingNodeValidator():
- super(null,
- allowedElements: [
- 'TEMPLATE'
- ],
- allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')),
- _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
- }
+ _TemplatingNodeValidator()
+ : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
+ super(null,
+ allowedElements: ['TEMPLATE'],
+ allowedAttributes:
+ _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
bool allowsAttribute(Element element, String attributeName, String value) {
if (super.allowsAttribute(element, attributeName, value)) {
@@ -42556,14 +42437,13 @@
return true;
}
- if (element.attributes['template'] == "" ) {
+ if (element.attributes['template'] == "") {
return _templateAttrs.contains(attributeName);
}
return false;
}
}
-
class _SvgNodeValidator implements NodeValidator {
bool allowsElement(Element element) {
if (element is svg.ScriptElement) {
@@ -42573,7 +42453,8 @@
// foreignobject tag as SvgElement. We don't want foreignobject contents
// anyway, so just remove the whole tree outright. And we can't rely
// on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
- if (element is svg.SvgElement && Element._safeTagName(element) == 'foreignObject') {
+ if (element is svg.SvgElement &&
+ Element._safeTagName(element) == 'foreignObject') {
return false;
}
if (element is svg.SvgElement) {
@@ -42625,7 +42506,7 @@
*/
class _WrappedList<E extends Node> extends ListBase<E>
implements NodeListWrapper {
- final List _list;
+ final List<Node> _list;
_WrappedList(this._list);
@@ -42645,13 +42526,13 @@
// List APIs
- E operator [](int index) => _list[index];
+ E operator [](int index) => _downcast/*<Node, E>*/(_list[index]);
void operator []=(int index, E value) { _list[index] = value; }
set length(int newLength) { _list.length = newLength; }
- void sort([int compare(E a, E b)]) { _list.sort(compare); }
+ void sort([int compare(E a, E b)]) { _list.sort((Node a, Node b) => compare(_downcast/*<Node, E>*/(a), _downcast/*<Node, E>*/(b))); }
int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
@@ -42659,7 +42540,7 @@
void insert(int index, E element) => _list.insert(index, element);
- E removeAt(int index) => _list.removeAt(index);
+ E removeAt(int index) => _downcast/*<Node, E>*/(_list.removeAt(index));
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_list.setRange(start, end, iterable, skipCount);
@@ -42681,8 +42562,8 @@
/**
* Iterator wrapper for _WrappedList.
*/
-class _WrappedIterator<E> implements Iterator<E> {
- Iterator _iterator;
+class _WrappedIterator<E extends Node> implements Iterator<E> {
+ Iterator<Node> _iterator;
_WrappedIterator(this._iterator);
@@ -42690,8 +42571,11 @@
return _iterator.moveNext();
}
- E get current => _iterator.current;
+ E get current => _downcast/*<Node, E>*/(_iterator.current);
}
+
+// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
+/*=To*/ _downcast/*<From, To extends From>*/(dynamic /*=From*/ x) => x;
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -43069,7 +42953,7 @@
Events get on => throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
- void _addEventListener([String type, EventListener listener, bool useCapture])
+ void _addEventListener(String type, EventListener listener, [bool useCapture])
=> throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
@@ -43080,8 +42964,8 @@
bool dispatchEvent(Event event) => throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
- void _removeEventListener([String type, EventListener listener,
- bool useCapture]) => throw new UnsupportedError(
+ void _removeEventListener(String type, EventListener listener,
+ [bool useCapture]) => throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
void removeEventListener(String type, EventListener listener,
@@ -43448,8 +43332,8 @@
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
' not arise as a result of event delegation.');
}
- var currentTarget = this.currentTarget;
- var target = this.target;
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
var matchedTarget;
do {
if (target.matches(_selector)) return target;
@@ -43480,17 +43364,25 @@
// BSD-style license that can be found in the LICENSE file.
-_wrapZone(callback(arg)) {
+// TODO(jacobr): remove these typedefs when dart:async supports generic types.
+typedef R _wrapZoneCallback<A, R>(A a);
+typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
+
+_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ callback) {
// For performance reasons avoid wrapping if we are in the root zone.
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindUnaryCallback(callback, runGuarded: true);
+ // TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindUnaryCallback(callback, runGuarded: true) as _wrapZoneCallback/*<A, R>*/;
}
-_wrapBinaryZone(callback(arg1, arg2)) {
+_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindBinaryCallback(callback, runGuarded: true);
+ // We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindBinaryCallback(callback, runGuarded: true) as _wrapZoneBinaryCallback/*<A, B, R>*/;
}
/**
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 30f39f7..78de601 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -401,7 +401,6 @@
'MimeType': () => MimeType.instanceRuntimeType,
'MimeTypeArray': () => MimeTypeArray.instanceRuntimeType,
'MouseEvent': () => MouseEvent.instanceRuntimeType,
- 'MutationEvent': () => _MutationEvent.instanceRuntimeType,
'MutationObserver': () => MutationObserver.instanceRuntimeType,
'MutationRecord': () => MutationRecord.instanceRuntimeType,
'NamedNodeMap': () => _NamedNodeMap.instanceRuntimeType,
@@ -806,12 +805,12 @@
*/
@DomName('AbstractWorker.errorEvent')
@DocsEditable()
- static const EventStreamProvider<ErrorEvent> errorEvent = const EventStreamProvider<ErrorEvent>('error');
+ static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
/// Stream of `error` events handled by this [AbstractWorker].
@DomName('AbstractWorker.onerror')
@DocsEditable()
- Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
+ Stream<Event> get onError => errorEvent.forTarget(this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -829,7 +828,7 @@
@DomName('HTMLAnchorElement.HTMLAnchorElement')
@DocsEditable()
factory AnchorElement({String href}) {
- var e = document.createElement("a");
+ AnchorElement e = document.createElement("a");
if (href != null) e.href = href;
return e;
}
@@ -3058,7 +3057,7 @@
@DomName('HTMLCanvasElement.HTMLCanvasElement')
@DocsEditable()
factory CanvasElement({int width, int height}) {
- var e = document.createElement("canvas");
+ CanvasElement e = document.createElement("canvas");
if (width != null) e.width = width;
if (height != null) e.height = height;
return e;
@@ -4462,7 +4461,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("CompositionEvent");
+ CompositionEvent e = document._createEvent("CompositionEvent");
e._initCompositionEvent(type, canBubble, cancelable, view, data);
@@ -9763,7 +9762,7 @@
factory DeviceOrientationEvent(String type,
{bool canBubble: true, bool cancelable: true, num alpha: 0, num beta: 0,
num gamma: 0, bool absolute: false}) {
- var e = document._createEvent("DeviceOrientationEvent");
+ DeviceOrientationEvent e = document._createEvent("DeviceOrientationEvent");
e._initDeviceOrientationEvent(type, canBubble, cancelable, alpha, beta,
gamma, absolute);
return e;
@@ -10324,7 +10323,7 @@
@DomName('Document.visibilityState')
@DocsEditable()
@Experimental() // untriaged
- String get visibilityState => _blink.BlinkDocument.instance.visibilityState_Getter_(this);
+ String get _visibilityState => _blink.BlinkDocument.instance.visibilityState_Getter_(this);
@DomName('Document.webkitFullscreenElement')
@DocsEditable()
@@ -10939,9 +10938,8 @@
* For details about CSS selector syntax, see the
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
- ElementList<Element> querySelectorAll(String selectors) {
- return new _FrozenElementList._wrap(_querySelectorAll(selectors));
- }
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
/**
* Alias for [querySelector]. Note this function is deprecated because its
@@ -10959,7 +10957,7 @@
@deprecated
@Experimental()
@DomName('Document.querySelectorAll')
- ElementList<Element> queryAll(String relativeSelectors) =>
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
querySelectorAll(relativeSelectors);
/// Checks if [registerElement] is supported on the current platform.
@@ -10986,6 +10984,13 @@
_blink.BlinkDocument.instance.createElementNS_Callback_3_(this, namespaceURI, qualifiedName, typeExtension);
}
+
+ @DomName('Document.visibilityState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @Experimental()
+ String get visibilityState => _visibilityState;
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -11024,7 +11029,7 @@
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -11041,8 +11046,9 @@
* For details about CSS selector syntax, see the
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
- ElementList<Element> querySelectorAll(String selectors) =>
- new _FrozenElementList._wrap(_querySelectorAll(selectors));
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
+
String get innerHtml {
final e = new Element.tag("div");
@@ -11099,9 +11105,8 @@
@deprecated
@Experimental()
@DomName('DocumentFragment.querySelectorAll')
- ElementList<Element> queryAll(String relativeSelectors) {
- return querySelectorAll(relativeSelectors);
- }
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
+ querySelectorAll(relativeSelectors);
// To suppress missing implicit constructor warnings.
factory DocumentFragment._() { throw new UnsupportedError("Not supported"); }
@@ -12481,7 +12486,7 @@
_filter(test, true);
}
- void _filter(bool test(var element), bool retainMatching) {
+ void _filter(bool test(Element element), bool retainMatching) {
var removed;
if (retainMatching) {
removed = _element.children.where((e) => !test(e));
@@ -13136,8 +13141,8 @@
// declared to return `ElementList`. This provides all the static analysis
// benefit so there is no need for this class have a constrained type parameter.
//
-class _FrozenElementList extends ListBase
- implements ElementList, NodeListWrapper {
+class _FrozenElementList<E extends Element> extends ListBase<E>
+ implements ElementList<E>, NodeListWrapper {
final List<Node> _nodeList;
var dartClass_instance;
@@ -13148,9 +13153,9 @@
int get length => _nodeList.length;
- Element operator [](int index) => _nodeList[index];
+ E operator [](int index) => _downcast/*<Node, E>*/(_nodeList[index]);
- void operator []=(int index, Element value) {
+ void operator []=(int index, E value) {
throw new UnsupportedError('Cannot modify list');
}
@@ -13158,7 +13163,7 @@
throw new UnsupportedError('Cannot modify list');
}
- void sort([Comparator<Element> compare]) {
+ void sort([Comparator<E> compare]) {
throw new UnsupportedError('Cannot sort list');
}
@@ -13166,11 +13171,11 @@
throw new UnsupportedError('Cannot shuffle list');
}
- Element get first => _nodeList.first;
+ E get first => _downcast/*<Node, E>*/(_nodeList.first);
- Element get last => _nodeList.last;
+ E get last => _downcast/*<Node, E>*/(_nodeList.last);
- Element get single => _nodeList.single;
+ E get single => _downcast/*<Node, E>*/(_nodeList.single);
CssClassSet get classes => new _MultiElementCssClassSet(this);
@@ -13184,7 +13189,7 @@
//
// as the code below converts the Iterable[value] to a string multiple
// times. Maybe compute the string and set className here.
- _nodeList.forEach((e) => e.classes = value);
+ forEach((e) => e.classes = value);
}
CssRect get contentEdge => new _ContentCssListRect(this);
@@ -13927,7 +13932,7 @@
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -13945,8 +13950,8 @@
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
@DomName('Element.querySelectorAll')
- ElementList<Element> querySelectorAll(String selectors) =>
- new _FrozenElementList._wrap(_querySelectorAll(selectors));
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
/**
* Alias for [querySelector]. Note this function is deprecated because its
@@ -13964,7 +13969,7 @@
@deprecated
@DomName('Element.querySelectorAll')
@Experimental()
- ElementList<Element> queryAll(String relativeSelectors) =>
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
querySelectorAll(relativeSelectors);
/**
@@ -14162,15 +14167,14 @@
throw new ArgumentError("The frames parameter should be a List of Maps "
"with frame information");
}
- var convertedFrames = frames;
- if (convertedFrames is Iterable) {
+ var convertedFrames;
+ if (frames is Iterable) {
convertedFrames = convertDartToNative_List(
frames.map(convertDartToNative_Dictionary).toList());
+ } else {
+ convertedFrames = frames;
}
- var convertedTiming = timing;
- if (convertedTiming is Map) {
- convertedTiming = convertDartToNative_Dictionary(convertedTiming);
- }
+ var convertedTiming = timing is Map ? convertDartToNative_Dictionary(timing) : timing;
return convertedTiming == null
? _animate(convertedFrames)
: _animate(convertedFrames, convertedTiming);
@@ -14498,7 +14502,7 @@
// Workaround for Safari bug. Was also previously Chrome bug 229142
// - URIs are not resolved in new doc.
- var base = _parseDocument.createElement('base');
+ BaseElement base = _parseDocument.createElement('base');
base.href = document.baseUri;
_parseDocument.head.append(base);
}
@@ -16640,7 +16644,7 @@
e._initEvent(name, canBubble, cancelable);
return e;
}
-
+
/** The CSS selector involved with event delegation. */
String _selector;
@@ -16654,8 +16658,8 @@
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
' not arise as a result of event delegation.');
}
- var currentTarget = this.currentTarget;
- var target = this.target;
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
var matchedTarget;
do {
if (target.matches(_selector)) return target;
@@ -16945,26 +16949,24 @@
}
class ElementEvents extends Events {
- /* Raw event target. */
- final Element _ptr;
static final webkitEvents = {
- 'animationend' : 'webkitAnimationEnd',
- 'animationiteration' : 'webkitAnimationIteration',
- 'animationstart' : 'webkitAnimationStart',
- 'fullscreenchange' : 'webkitfullscreenchange',
+ 'animationend' : 'webkitAnimationEnd',
+ 'animationiteration' : 'webkitAnimationIteration',
+ 'animationstart' : 'webkitAnimationStart',
+ 'fullscreenchange' : 'webkitfullscreenchange',
'fullscreenerror' : 'webkitfullscreenerror',
- 'keyadded' : 'webkitkeyadded',
- 'keyerror' : 'webkitkeyerror',
- 'keymessage' : 'webkitkeymessage',
- 'needkey' : 'webkitneedkey',
- 'pointerlockchange' : 'webkitpointerlockchange',
- 'pointerlockerror' : 'webkitpointerlockerror',
- 'resourcetimingbufferfull' : 'webkitresourcetimingbufferfull',
+ 'keyadded' : 'webkitkeyadded',
+ 'keyerror' : 'webkitkeyerror',
+ 'keymessage' : 'webkitkeymessage',
+ 'needkey' : 'webkitneedkey',
+ 'pointerlockchange' : 'webkitpointerlockchange',
+ 'pointerlockerror' : 'webkitpointerlockerror',
+ 'resourcetimingbufferfull' : 'webkitresourcetimingbufferfull',
'transitionend': 'webkitTransitionEnd',
'speechchange' : 'webkitSpeechChange'
};
- ElementEvents(Element ptr) : this._ptr = ptr, super(ptr);
+ ElementEvents(Element ptr) : super(ptr);
Stream operator [](String type) {
if (webkitEvents.keys.contains(type.toLowerCase())) {
@@ -18707,7 +18709,10 @@
}
int watchId;
- var controller;
+ // TODO(jacobr): it seems like a bug that we have to specifiy the static
+ // type here for controller.stream to have the right type.
+ // dartbug.com/26278
+ StreamController<Geoposition> controller;
controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
@@ -19758,11 +19763,11 @@
@DomName('HTMLCollection.item')
@DocsEditable()
- Element item(int index) => _blink.BlinkHTMLCollection.instance.item_Callback_1_(this, index);
+ Node item(int index) => _blink.BlinkHTMLCollection.instance.item_Callback_1_(this, index);
@DomName('HTMLCollection.namedItem')
@DocsEditable()
- Element namedItem(String name) => _blink.BlinkHTMLCollection.instance.namedItem_Callback_1_(this, name);
+ Object namedItem(String name) => (_blink.BlinkHTMLCollection.instance.namedItem_Callback_1_(this, name));
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -19894,59 +19899,6 @@
_webkitExitFullscreen();
}
- /**
- * Returns the element, if any, that is currently displayed in fullscreen.
- *
- * Returns null if there is currently no fullscreen element. You can use
- * this to determine if the page is in fullscreen mode.
- *
- * myVideo = new VideoElement();
- * if (document.fullscreenElement == null) {
- * myVideo.requestFullscreen();
- * print(document.fullscreenElement == myVideo); // true
- * }
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenElement')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- Element get fullscreenElement => _webkitFullscreenElement;
-
- /**
- * Returns true if this document can display elements in fullscreen mode.
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenEnabled')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get fullscreenEnabled => _webkitFullscreenEnabled;
-
- @DomName('Document.webkitHidden')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get hidden => _webkitHidden;
-
- @DomName('Document.visibilityState')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.FIREFOX)
- @SupportedBrowser(SupportedBrowser.IE, '10')
- @Experimental()
- String get visibilityState => _webkitVisibilityState;
/**
* Internal routine to find the DOM JS class name being extended for custom
@@ -22126,7 +22078,7 @@
@DomName('HTMLImageElement.HTMLImageElement')
@DocsEditable()
factory ImageElement({String src, int width, int height}) {
- var e = document.createElement("img");
+ ImageElement e = document.createElement("img");
if (src != null) e.src = src;
if (width != null) e.width = width;
if (height != null) e.height = height;
@@ -22335,7 +22287,7 @@
ButtonInputElement {
factory InputElement({String type}) {
- var e = document.createElement("input");
+ InputElement e = document.createElement("input");
if (type != null) {
try {
// IE throws an exception for unknown types.
@@ -25910,11 +25862,11 @@
factory MessageEvent(String type,
{bool canBubble: false, bool cancelable: false, Object data,
String origin, String lastEventId,
- Window source, List messagePorts}) {
+ Window source, List<MessagePort> messagePorts}) {
if (source == null) {
source = window;
}
- var event = document._createEvent("MessageEvent");
+ MessageEvent event = document._createEvent("MessageEvent");
event._initMessageEvent(type, canBubble, cancelable, data, origin,
lastEventId, source, messagePorts);
return event;
@@ -26849,20 +26801,6 @@
@deprecated
Node get toElement => _blink.BlinkMouseEvent.instance.toElement_Getter_(this);
- @DomName('MouseEvent.webkitMovementX')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- int get _webkitMovementX => _blink.BlinkMouseEvent.instance.webkitMovementX_Getter_(this);
-
- @DomName('MouseEvent.webkitMovementY')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- int get _webkitMovementY => _blink.BlinkMouseEvent.instance.webkitMovementY_Getter_(this);
-
@DomName('MouseEvent.which')
@DocsEditable()
@Experimental() // untriaged
@@ -26897,9 +26835,9 @@
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_webkitMovementX, _webkitMovementY);
+ Point get movement => new Point(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
@@ -27789,7 +27727,7 @@
set nodes(Iterable<Node> value) {
// Copy list first since we don't want liveness during iteration.
// TODO(jacobr): there is a better way to do this.
- List copy = new List.from(value);
+ var copy = value.toList();
text = '';
for (Node node in copy) {
append(node);
@@ -32917,8 +32855,7 @@
// Override default options, since IE returns SelectElement itself and it
// does not operate as a List.
List<OptionElement> get options {
- var options = this.querySelectorAll('option').where(
- (e) => e is OptionElement).toList();
+ var options = new List<OptionElement>.from(this.querySelectorAll('option'));
return new UnmodifiableListView(options);
}
@@ -35123,11 +35060,11 @@
}
// TODO(nweiz): update this when maps support lazy iteration
- bool containsValue(String value) => values.any((e) => e == value);
+ bool containsValue(Object value) => values.any((e) => e == value);
- bool containsKey(String key) => _getItem(key) != null;
+ bool containsKey(Object key) => _getItem(key) != null;
- String operator [](String key) => _getItem(key);
+ String operator [](Object key) => _getItem(key);
void operator []=(String key, String value) { _setItem(key, value); }
@@ -35136,7 +35073,7 @@
return this[key];
}
- String remove(String key) {
+ String remove(Object key) {
final value = this[key];
_removeItem(key);
return value;
@@ -35154,13 +35091,13 @@
}
Iterable<String> get keys {
- final keys = [];
+ final keys = <String>[];
forEach((k, v) => keys.add(k));
return keys;
}
Iterable<String> get values {
- final values = [];
+ final values = <String>[];
forEach((k, v) => values.add(v));
return values;
}
@@ -35262,7 +35199,7 @@
{bool canBubble: false, bool cancelable: false, String key, String oldValue,
String newValue, String url, Storage storageArea}) {
- var e = document._createEvent("StorageEvent");
+ StorageEvent e = document._createEvent("StorageEvent");
e._initStorageEvent(type, canBubble, cancelable, key, oldValue,
newValue, url, storageArea);
return e;
@@ -36407,7 +36344,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("TextEvent");
+ TextEvent e = document._createEvent("TextEvent");
e._initTextEvent(type, canBubble, cancelable, view, data);
return e;
}
@@ -37090,7 +37027,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("TouchEvent");
+ TouchEvent e = document._createEvent("TouchEvent");
e._initTouchEvent(touches, targetTouches, changedTouches, type, view,
screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey);
return e;
@@ -37606,7 +37543,7 @@
if (view == null) {
view = window;
}
- final e = document._createEvent("UIEvent");
+ UIEvent e = document._createEvent("UIEvent");
e._initUIEvent(type, canBubble, cancelable, view, detail);
return e;
}
@@ -41741,16 +41678,6 @@
@Experimental() // untriaged
String get nodeValue => _blink.BlinkAttr.instance.nodeValue_Getter_(this);
- @DomName('Attr.textContent')
- @DocsEditable()
- @Experimental() // untriaged
- String get text => _blink.BlinkAttr.instance.textContent_Getter_(this);
-
- @DomName('Attr.textContent')
- @DocsEditable()
- @Experimental() // untriaged
- set text(String value) => _blink.BlinkAttr.instance.textContent_Setter_(this, value);
-
@DomName('Attr.value')
@DocsEditable()
String get value => _blink.BlinkAttr.instance.value_Getter_(this);
@@ -42699,36 +42626,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-
-@DomName('MutationEvent')
-// http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents
-@deprecated
-class _MutationEvent extends Event {
- factory _MutationEvent(String type,
- {bool canBubble: false, bool cancelable: false, Node relatedNode,
- String prevValue, String newValue, String attrName, int attrChange: 0}) {
-
- var event = document._createEvent('MutationEvent');
- event._initMutationEvent(type, canBubble, cancelable, relatedNode,
- prevValue, newValue, attrName, attrChange);
- return event;
- }
- // To suppress missing implicit constructor warnings.
- factory _MutationEvent._() { throw new UnsupportedError("Not supported"); }
-
-
- @Deprecated("Internal Use Only")
- external static Type get instanceRuntimeType;
-
- @Deprecated("Internal Use Only")
- _MutationEvent.internal_() : super.internal_();
-
-
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
// WARNING: Do not edit - generated code.
@@ -43378,7 +43275,7 @@
other.forEach((k, v) { this[k] = v; });
}
- bool containsValue(String value) {
+ bool containsValue(Object value) {
for (var v in this.values) {
if (value == v) {
return true;
@@ -43410,10 +43307,11 @@
Iterable<String> get keys {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var keys = new List<String>();
+ var keys = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- keys.add(attributes[i].name);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ keys.add(attr.name);
}
}
return keys;
@@ -43422,10 +43320,11 @@
Iterable<String> get values {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var values = new List<String>();
+ var values = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- values.add(attributes[i].value);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ values.add(attr.value);
}
}
return values;
@@ -43456,11 +43355,11 @@
_ElementAttributeMap(Element element): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttribute(key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttribute(key);
}
@@ -43468,7 +43367,7 @@
_element.setAttribute(key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = _element.getAttribute(key);
_element._removeAttribute(key);
return value;
@@ -43493,11 +43392,11 @@
_NamespacedAttributeMap(Element element, this._namespace): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttributeNS(_namespace, key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttributeNS(_namespace, key);
}
@@ -43505,7 +43404,7 @@
_element.setAttributeNS(_namespace, key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = this[key];
_element._removeAttributeNS(_namespace, key);
return value;
@@ -43539,11 +43438,11 @@
}
// TODO: Use lazy iterator when it is available on Map.
- bool containsValue(String value) => values.any((v) => v == value);
+ bool containsValue(Object value) => values.any((v) => v == value);
- bool containsKey(String key) => _attributes.containsKey(_attr(key));
+ bool containsKey(Object key) => _attributes.containsKey(_attr(key));
- String operator [](String key) => _attributes[_attr(key)];
+ String operator [](Object key) => _attributes[_attr(key)];
void operator []=(String key, String value) {
_attributes[_attr(key)] = value;
@@ -43552,7 +43451,7 @@
String putIfAbsent(String key, String ifAbsent()) =>
_attributes.putIfAbsent(_attr(key), ifAbsent);
- String remove(String key) => _attributes.remove(_attr(key));
+ String remove(Object key) => _attributes.remove(_attr(key));
void clear() {
// Needs to operate on a snapshot since we are mutating the collection.
@@ -43570,7 +43469,7 @@
}
Iterable<String> get keys {
- final keys = new List<String>();
+ final keys = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
keys.add(_strip(key));
@@ -43580,7 +43479,7 @@
}
Iterable<String> get values {
- final values = new List<String>();
+ final values = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
values.add(value);
@@ -43811,7 +43710,7 @@
* * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
* from WHATWG.
*/
- void postMessage(var message, String targetOrigin, [List messagePorts]);
+ void postMessage(var message, String targetOrigin, [List<MessagePort> messagePorts]);
}
abstract class LocationBase {
@@ -43865,7 +43764,7 @@
* [value] must be a valid 'token' representing a single class, i.e. a
* non-empty string containing no whitespace.
*/
- bool contains(String value);
+ bool contains(Object value);
/**
* Add the class [value] to element.
@@ -43917,7 +43816,7 @@
* Each element of [iterable] must be a valid 'token' representing a single
* class, i.e. a non-empty string containing no whitespace.
*/
- void removeAll(Iterable<String> iterable);
+ void removeAll(Iterable<Object> iterable);
/**
* Toggles all classes specified in [iterable] on element.
@@ -44033,7 +43932,7 @@
*/
class _ContentCssRect extends CssRect {
- _ContentCssRect(element) : super(element);
+ _ContentCssRect(Element element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
@@ -44054,9 +43953,11 @@
if (newHeight is Dimension) {
if (newHeight.value < 0) newHeight = new Dimension.px(0);
_element.style.height = newHeight.toString();
- } else {
+ } else if (newHeight is num) {
if (newHeight < 0) newHeight = 0;
_element.style.height = '${newHeight}px';
+ } else {
+ throw new ArgumentError("newHeight is not a Dimension or num");
}
}
@@ -44072,9 +43973,11 @@
if (newWidth is Dimension) {
if (newWidth.value < 0) newWidth = new Dimension.px(0);
_element.style.width = newWidth.toString();
- } else {
+ } else if (newWidth is num) {
if (newWidth < 0) newWidth = 0;
_element.style.width = '${newWidth}px';
+ } else {
+ throw new ArgumentError("newWidth is not a Dimension or num");
}
}
@@ -44091,7 +43994,7 @@
class _ContentCssListRect extends _ContentCssRect {
List<Element> _elementList;
- _ContentCssListRect(elementList) : super(elementList.first) {
+ _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
_elementList = elementList;
}
@@ -44180,10 +44083,10 @@
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
-abstract class CssRect extends MutableRectangle<num> {
+abstract class CssRect implements Rectangle<num> {
Element _element;
- CssRect(this._element) : super(0, 0, 0, 0);
+ CssRect(this._element);
num get left;
@@ -44276,6 +44179,102 @@
}
return val;
}
+
+ // TODO(jacobr): these methods are duplicated from _RectangleBase in dart:math
+ // Ideally we would provide a RectangleMixin class that provides this implementation.
+ // In an ideal world we would exp
+ /** The x-coordinate of the right edge. */
+ num get right => left + width;
+ /** The y-coordinate of the bottom edge. */
+ num get bottom => top + height;
+
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is !Rectangle) return false;
+ return left == other.left && top == other.top && right == other.right &&
+ bottom == other.bottom;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
+ right.hashCode, bottom.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
+ */
+ Rectangle<num> intersection(Rectangle<num> other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle<num>(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle<num> boundingBox(Rectangle<num> other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle<num>(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point<num> get topLeft => new Point<num>(this.left, this.top);
+ Point<num> get topRight => new Point<num>(this.left + this.width, this.top);
+ Point<num> get bottomRight => new Point<num>(this.left + this.width,
+ this.top + this.height);
+ Point<num> get bottomLeft => new Point<num>(this.left,
+ this.top + this.height);
}
final _HEIGHT = ['top', 'bottom'];
@@ -44406,7 +44405,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
- new _EventStream(e, _eventType, useCapture);
+ new _EventStream<T>(e, _eventType, useCapture);
/**
* Gets an [ElementEventStream] for this event type, on the specified element.
@@ -44430,7 +44429,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -44501,8 +44500,8 @@
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
@@ -44516,6 +44515,11 @@
}
}
+bool _matchesWithAncestors(Event event, String selector) {
+ var target = event.target;
+ return target is Element ? target.matchesWithAncestors(selector) : false;
+}
+
/**
* Adapter for exposing DOM Element events as streams, while also allowing
* event delegation.
@@ -44526,7 +44530,7 @@
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -44550,7 +44554,7 @@
this._targetList, this._eventType, this._useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -44560,37 +44564,46 @@
{ Function onError,
void onDone(),
bool cancelOnError}) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, _useCapture));
+ pool.add(new _EventStream<T>(target, _eventType, _useCapture));
}
return pool.stream.listen(onData, onError: onError, onDone: onDone,
cancelOnError: cancelOnError);
}
StreamSubscription<T> capture(void onData(T event)) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, true));
+ pool.add(new _EventStream<T>(target, _eventType, true));
}
return pool.stream.listen(onData);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
}
+// We would like this to just be EventListener<T> but that typdef cannot
+// use generics until dartbug/26276 is fixed.
+typedef _EventListener<T extends Event>(T event);
+
class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
int _pauseCount = 0;
EventTarget _target;
final String _eventType;
- var _onData;
+ EventListener _onData;
final bool _useCapture;
- _EventStreamSubscription(this._target, this._eventType, onData,
- this._useCapture) : _onData = _wrapZone(onData) {
+ // TODO(jacobr): for full strong mode correctness we should write
+ // _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((e) => onData(e as T))
+ // but that breaks 114 co19 tests as well as multiple html tests as it is reasonable
+ // to pass the wrong type of event object to an event listener as part of a
+ // test.
+ _EventStreamSubscription(this._target, this._eventType, void onData(T event),
+ this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@@ -44612,8 +44625,7 @@
}
// Remove current event listener.
_unlisten();
-
- _onData = _wrapZone(handleData);
+ _onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@@ -44692,8 +44704,8 @@
onDone: onDone, cancelOnError: cancelOnError);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> _streamController.stream;
bool get isBroadcast => true;
@@ -44784,16 +44796,16 @@
const _CustomEventStreamProvider(this._eventTypeGetter);
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
- return new _EventStream(e, _eventTypeGetter(e), useCapture);
+ return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> _forElementList(ElementList e,
{bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
String getEventType(EventTarget target) {
@@ -46172,7 +46184,7 @@
* The set of keys that have been pressed down without seeing their
* corresponding keyup event.
*/
- final List<KeyboardEvent> _keyDownList = <KeyboardEvent>[];
+ final List<KeyEvent> _keyDownList = <KeyEvent>[];
/** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
final String _type;
@@ -46231,8 +46243,9 @@
* General constructor, performs basic initialization for our improved
* KeyboardEvent controller.
*/
- _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
+ _KeyboardEventHandler(this._type):
+ _stream = new _CustomKeyEventStreamImpl('event'), _target = null,
+ super(_EVENT_TYPE);
/**
* Hook up all event listeners under the covers so we can estimate keycodes
@@ -46540,7 +46553,6 @@
// BSD-style license that can be found in the LICENSE file.
-
/**
* Class which helps construct standard node validation policies.
*
@@ -46558,11 +46570,9 @@
* appropriate.
*/
class NodeValidatorBuilder implements NodeValidator {
-
final List<NodeValidator> _validators = <NodeValidator>[];
- NodeValidatorBuilder() {
- }
+ NodeValidatorBuilder() {}
/**
* Creates a new NodeValidatorBuilder which accepts common constructs.
@@ -46691,29 +46701,17 @@
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
+ var attrs = attributes
+ ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
if (uriPolicy == null) {
uriPolicy = new UriPolicy();
}
add(new _CustomElementNodeValidator(
- uriPolicy,
- [tagNameUpper],
- attrs,
- uriAttrs,
- false,
- true));
+ uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
}
/**
@@ -46728,37 +46726,26 @@
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var baseNameUpper = baseName.toUpperCase();
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
+ var attrs = attributes
+ ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
if (uriPolicy == null) {
uriPolicy = new UriPolicy();
}
- add(new _CustomElementNodeValidator(
- uriPolicy,
- [tagNameUpper, baseNameUpper],
- attrs,
- uriAttrs,
- true,
- false));
+ add(new _CustomElementNodeValidator(uriPolicy,
+ [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
}
- void allowElement(String tagName, {UriPolicy uriPolicy,
- Iterable<String> attributes,
- Iterable<String> uriAttributes}) {
-
- allowCustomElement(tagName, uriPolicy: uriPolicy,
+ void allowElement(String tagName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ allowCustomElement(tagName,
+ uriPolicy: uriPolicy,
attributes: attributes,
uriAttributes: uriAttributes);
}
@@ -46789,8 +46776,8 @@
}
bool allowsAttribute(Element element, String attributeName, String value) {
- return _validators.any(
- (v) => v.allowsAttribute(element, attributeName, value));
+ return _validators
+ .any((v) => v.allowsAttribute(element, attributeName, value));
}
}
@@ -46801,76 +46788,70 @@
final UriPolicy uriPolicy;
factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
- return new _SimpleNodeValidator(uriPolicy,
- allowedElements: const [
- 'A',
- 'FORM'],
- allowedAttributes: const [
- 'A::accesskey',
- 'A::coords',
- 'A::hreflang',
- 'A::name',
- 'A::shape',
- 'A::tabindex',
- 'A::target',
- 'A::type',
- 'FORM::accept',
- 'FORM::autocomplete',
- 'FORM::enctype',
- 'FORM::method',
- 'FORM::name',
- 'FORM::novalidate',
- 'FORM::target',
- ],
- allowedUriAttributes: const [
- 'A::href',
- 'FORM::action',
- ]);
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'A',
+ 'FORM'
+ ], allowedAttributes: const [
+ 'A::accesskey',
+ 'A::coords',
+ 'A::hreflang',
+ 'A::name',
+ 'A::shape',
+ 'A::tabindex',
+ 'A::target',
+ 'A::type',
+ 'FORM::accept',
+ 'FORM::autocomplete',
+ 'FORM::enctype',
+ 'FORM::method',
+ 'FORM::name',
+ 'FORM::novalidate',
+ 'FORM::target',
+ ], allowedUriAttributes: const [
+ 'A::href',
+ 'FORM::action',
+ ]);
}
factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
- return new _SimpleNodeValidator(uriPolicy,
- allowedElements: const [
- 'IMG'
- ],
- allowedAttributes: const [
- 'IMG::align',
- 'IMG::alt',
- 'IMG::border',
- 'IMG::height',
- 'IMG::hspace',
- 'IMG::ismap',
- 'IMG::name',
- 'IMG::usemap',
- 'IMG::vspace',
- 'IMG::width',
- ],
- allowedUriAttributes: const [
- 'IMG::src',
- ]);
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'IMG'
+ ], allowedAttributes: const [
+ 'IMG::align',
+ 'IMG::alt',
+ 'IMG::border',
+ 'IMG::height',
+ 'IMG::hspace',
+ 'IMG::ismap',
+ 'IMG::name',
+ 'IMG::usemap',
+ 'IMG::vspace',
+ 'IMG::width',
+ ], allowedUriAttributes: const [
+ 'IMG::src',
+ ]);
}
factory _SimpleNodeValidator.allowTextElements() {
- return new _SimpleNodeValidator(null,
- allowedElements: const [
- 'B',
- 'BLOCKQUOTE',
- 'BR',
- 'EM',
- 'H1',
- 'H2',
- 'H3',
- 'H4',
- 'H5',
- 'H6',
- 'HR',
- 'I',
- 'LI',
- 'OL',
- 'P',
- 'SPAN',
- 'UL',
- ]);
+ return new _SimpleNodeValidator(null, allowedElements: const [
+ 'B',
+ 'BLOCKQUOTE',
+ 'BR',
+ 'EM',
+ 'H1',
+ 'H2',
+ 'H3',
+ 'H4',
+ 'H5',
+ 'H6',
+ 'HR',
+ 'I',
+ 'LI',
+ 'OL',
+ 'P',
+ 'SPAN',
+ 'UL',
+ ]);
}
/**
@@ -46879,15 +46860,16 @@
* lowercase attribute name. For example `'IMG:src'`.
*/
_SimpleNodeValidator(this.uriPolicy,
- {Iterable<String> allowedElements, Iterable<String> allowedAttributes,
- Iterable<String> allowedUriAttributes}) {
+ {Iterable<String> allowedElements,
+ Iterable<String> allowedAttributes,
+ Iterable<String> allowedUriAttributes}) {
this.allowedElements.addAll(allowedElements ?? const []);
allowedAttributes = allowedAttributes ?? const [];
allowedUriAttributes = allowedUriAttributes ?? const [];
- var legalAttributes = allowedAttributes.where(
- (x) => !_Html5NodeValidator._uriAttributes.contains(x));
- var extraUriAttributes = allowedAttributes.where(
- (x) => _Html5NodeValidator._uriAttributes.contains(x));
+ var legalAttributes = allowedAttributes
+ .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
+ var extraUriAttributes = allowedAttributes
+ .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
this.allowedAttributes.addAll(legalAttributes);
this.allowedUriAttributes.addAll(allowedUriAttributes);
this.allowedUriAttributes.addAll(extraUriAttributes);
@@ -46920,19 +46902,19 @@
final bool allowTypeExtension;
final bool allowCustomTag;
- _CustomElementNodeValidator(UriPolicy uriPolicy,
+ _CustomElementNodeValidator(
+ UriPolicy uriPolicy,
Iterable<String> allowedElements,
Iterable<String> allowedAttributes,
Iterable<String> allowedUriAttributes,
bool allowTypeExtension,
- bool allowCustomTag):
-
- super(uriPolicy,
- allowedElements: allowedElements,
- allowedAttributes: allowedAttributes,
- allowedUriAttributes: allowedUriAttributes),
- this.allowTypeExtension = allowTypeExtension == true,
- this.allowCustomTag = allowCustomTag == true;
+ bool allowCustomTag)
+ : this.allowTypeExtension = allowTypeExtension == true,
+ this.allowCustomTag = allowCustomTag == true,
+ super(uriPolicy,
+ allowedElements: allowedElements,
+ allowedAttributes: allowedAttributes,
+ allowedUriAttributes: allowedUriAttributes);
bool allowsElement(Element element) {
if (allowTypeExtension) {
@@ -46942,12 +46924,14 @@
allowedElements.contains(Element._safeTagName(element));
}
}
- return allowCustomTag && allowedElements.contains(Element._safeTagName(element));
+ return allowCustomTag &&
+ allowedElements.contains(Element._safeTagName(element));
}
bool allowsAttribute(Element element, String attributeName, String value) {
- if (allowsElement(element)) {
- if (allowTypeExtension && attributeName == 'is' &&
+ if (allowsElement(element)) {
+ if (allowTypeExtension &&
+ attributeName == 'is' &&
allowedElements.contains(value.toUpperCase())) {
return true;
}
@@ -46958,19 +46942,22 @@
}
class _TemplatingNodeValidator extends _SimpleNodeValidator {
- static const _TEMPLATE_ATTRS =
- const <String>['bind', 'if', 'ref', 'repeat', 'syntax'];
+ static const _TEMPLATE_ATTRS = const <String>[
+ 'bind',
+ 'if',
+ 'ref',
+ 'repeat',
+ 'syntax'
+ ];
final Set<String> _templateAttrs;
- _TemplatingNodeValidator():
- super(null,
- allowedElements: [
- 'TEMPLATE'
- ],
- allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')),
- _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
- }
+ _TemplatingNodeValidator()
+ : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
+ super(null,
+ allowedElements: ['TEMPLATE'],
+ allowedAttributes:
+ _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
bool allowsAttribute(Element element, String attributeName, String value) {
if (super.allowsAttribute(element, attributeName, value)) {
@@ -46981,14 +46968,13 @@
return true;
}
- if (element.attributes['template'] == "" ) {
+ if (element.attributes['template'] == "") {
return _templateAttrs.contains(attributeName);
}
return false;
}
}
-
class _SvgNodeValidator implements NodeValidator {
bool allowsElement(Element element) {
if (element is svg.ScriptElement) {
@@ -46998,7 +46984,8 @@
// foreignobject tag as SvgElement. We don't want foreignobject contents
// anyway, so just remove the whole tree outright. And we can't rely
// on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
- if (element is svg.SvgElement && Element._safeTagName(element) == 'foreignObject') {
+ if (element is svg.SvgElement &&
+ Element._safeTagName(element) == 'foreignObject') {
return false;
}
if (element is svg.SvgElement) {
@@ -47345,7 +47332,7 @@
*/
class _WrappedList<E extends Node> extends ListBase<E>
implements NodeListWrapper {
- final List _list;
+ final List<Node> _list;
_WrappedList(this._list);
@@ -47365,13 +47352,13 @@
// List APIs
- E operator [](int index) => _list[index];
+ E operator [](int index) => _downcast/*<Node, E>*/(_list[index]);
void operator []=(int index, E value) { _list[index] = value; }
set length(int newLength) { _list.length = newLength; }
- void sort([int compare(E a, E b)]) { _list.sort(compare); }
+ void sort([int compare(E a, E b)]) { _list.sort((Node a, Node b) => compare(_downcast/*<Node, E>*/(a), _downcast/*<Node, E>*/(b))); }
int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
@@ -47379,7 +47366,7 @@
void insert(int index, E element) => _list.insert(index, element);
- E removeAt(int index) => _list.removeAt(index);
+ E removeAt(int index) => _downcast/*<Node, E>*/(_list.removeAt(index));
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_list.setRange(start, end, iterable, skipCount);
@@ -47401,8 +47388,8 @@
/**
* Iterator wrapper for _WrappedList.
*/
-class _WrappedIterator<E> implements Iterator<E> {
- Iterator _iterator;
+class _WrappedIterator<E extends Node> implements Iterator<E> {
+ Iterator<Node> _iterator;
_WrappedIterator(this._iterator);
@@ -47410,8 +47397,11 @@
return _iterator.moveNext();
}
- E get current => _iterator.current;
+ E get current => _downcast/*<Node, E>*/(_iterator.current);
}
+
+// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
+/*=To*/ _downcast/*<From, To extends From>*/(dynamic /*=From*/ x) => x;
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -47852,17 +47842,25 @@
// BSD-style license that can be found in the LICENSE file.
-_wrapZone(callback(arg)) {
+// TODO(jacobr): remove these typedefs when dart:async supports generic types.
+typedef R _wrapZoneCallback<A, R>(A a);
+typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
+
+_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ callback) {
// For performance reasons avoid wrapping if we are in the root zone.
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindUnaryCallback(callback, runGuarded: true);
+ // TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindUnaryCallback(callback, runGuarded: true) as _wrapZoneCallback/*<A, R>*/;
}
-_wrapBinaryZone(callback(arg1, arg2)) {
+_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindBinaryCallback(callback, runGuarded: true);
+ // We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindBinaryCallback(callback, runGuarded: true) as _wrapZoneBinaryCallback/*<A, B, R>*/;
}
/**
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index de0d423..179b4e8 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.dart
@@ -351,14 +351,3 @@
}
return imageData;
}
-
-const String _serializedScriptValue =
- 'num|String|bool|'
- 'JSExtendableArray|=Object|'
- 'Blob|File|NativeByteBuffer|NativeTypedData'
- // TODO(sra): Add Date, RegExp.
- ;
-const annotation_Creates_SerializedScriptValue =
- const Creates(_serializedScriptValue);
-const annotation_Returns_SerializedScriptValue =
- const Returns(_serializedScriptValue);
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index b5a1064..15f9b2a 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -91,3 +91,14 @@
var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
return completer.future;
}
+
+const String _serializedScriptValue =
+ 'num|String|bool|'
+ 'JSExtendableArray|=Object|'
+ 'Blob|File|NativeByteBuffer|NativeTypedData'
+ // TODO(sra): Add Date, RegExp.
+ ;
+const annotation_Creates_SerializedScriptValue =
+ const Creates(_serializedScriptValue);
+const annotation_Returns_SerializedScriptValue =
+ const Returns(_serializedScriptValue);
diff --git a/sdk/lib/html/html_common/css_class_set.dart b/sdk/lib/html/html_common/css_class_set.dart
index 9c4b443..3e72600 100644
--- a/sdk/lib/html/html_common/css_class_set.dart
+++ b/sdk/lib/html/html_common/css_class_set.dart
@@ -56,11 +56,13 @@
String join([String separator = ""]) => readClasses().join(separator);
- Iterable map(f(String element)) => readClasses().map(f);
+ Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(String e)) =>
+ readClasses().map/*<T>*/(f);
Iterable<String> where(bool f(String element)) => readClasses().where(f);
- Iterable expand(Iterable f(String element)) => readClasses().expand(f);
+ Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(String element)) =>
+ readClasses().expand/*<T>*/(f);
bool every(bool f(String element)) => readClasses().every(f);
@@ -76,10 +78,11 @@
return readClasses().reduce(combine);
}
- dynamic fold(dynamic initialValue,
- dynamic combine(dynamic previousValue, String element)) {
- return readClasses().fold(initialValue, combine);
+ dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+ dynamic/*=T*/ combine(var/*=T*/ previousValue, String element)) {
+ return readClasses().fold/*<T>*/(initialValue, combine);
}
+
// interface Collection - END
// interface Set - BEGIN
@@ -145,7 +148,7 @@
* [removeClass](http://api.jquery.com/removeClass/).
*/
void removeAll(Iterable<Object> iterable) {
- modify((s) => s.removeAll(iterable.map(_validateToken)));
+ modify((s) => s.removeAll(iterable));
}
/**
@@ -183,7 +186,7 @@
Set<String> union(Set<String> other) =>
readClasses().union(other);
- Set<String> difference(Set<String> other) =>
+ Set<String> difference(Set<Object> other) =>
readClasses().difference(other);
String get first => readClasses().first;
@@ -221,7 +224,7 @@
* After f returns, the modified set is written to the
* className property of this element.
*/
- modify( f(Set<String> s)) {
+ modify(f(Set<String> s)) {
Set<String> s = readClasses();
var ret = f(s);
writeClasses(s);
diff --git a/sdk/lib/html/html_common/filtered_element_list.dart b/sdk/lib/html/html_common/filtered_element_list.dart
index e9e4718..d4d40ae 100644
--- a/sdk/lib/html/html_common/filtered_element_list.dart
+++ b/sdk/lib/html/html_common/filtered_element_list.dart
@@ -26,12 +26,8 @@
// We can't memoize this, since it's possible that children will be messed
// with externally to this class.
- //
- // We can't use where directly because the types don't agree and there's
- // no way to cast it, so take advantage of being in the SDK to construct
- // a WhereIterable directly. Even so it has to be of dynamic.
Iterable<Element> get _iterable =>
- new WhereIterable(_childNodes, (n) => n is Element);
+ _childNodes.where((n) => n is Element).map/*<Element>*/((n) => n as Element);
List<Element> get _filtered =>
new List<Element>.from(_iterable, growable: false);
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index f969eb3..65ebfc6 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -553,14 +553,14 @@
@DomName('IDBFactory.deleteDatabase')
Future<IdbFactory> deleteDatabase(String name,
- {void onBlocked(Event)}) {
+ {void onBlocked(Event e)}) {
try {
var request = _deleteDatabase(name);
if (onBlocked != null) {
request.onBlocked.listen(onBlocked);
}
- var completer = new Completer.sync();
+ var completer = new Completer<IdbFactory>.sync();
request.onSuccess.listen((e) {
completer.complete(this);
});
@@ -630,12 +630,13 @@
* Ties a request to a completer, so the completer is completed when it succeeds
* and errors out when the request errors.
*/
-Future _completeRequest(Request request) {
- var completer = new Completer.sync();
+Future/*<T>*/ _completeRequest/*<T>*/(Request request) {
+ var completer = new Completer/*<T>*/.sync();
// TODO: make sure that completer.complete is synchronous as transactions
// may be committed if the result is not processed immediately.
request.onSuccess.listen((e) {
- completer.complete(request.result);
+ var result = _cast/*<T>*/(request.result);
+ completer.complete(result);
});
request.onError.listen(completer.completeError);
return completer.future;
@@ -1175,18 +1176,18 @@
/**
* Helper for iterating over cursors in a request.
*/
- static Stream<Cursor> _cursorStreamFromResult(Request request,
+ static Stream/*<T>*/ _cursorStreamFromResult/*<T extends Cursor>*/(Request request,
bool autoAdvance) {
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController(sync: true);
+ var controller = new StreamController/*<T>*/(sync: true);
//TODO: Report stacktrace once issue 4061 is resolved.
request.onError.listen(controller.addError);
request.onSuccess.listen((e) {
- Cursor cursor = request.result;
+ var cursor = _cast/*<T>*/(request.result);
if (cursor == null) {
controller.close();
} else {
@@ -1199,6 +1200,9 @@
return controller.stream;
}
}
+
+// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
+/*=To*/ _cast/*<To>*/(dynamic x) => x;
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 39c78ed..584abb0 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -497,14 +497,14 @@
@DomName('IDBFactory.deleteDatabase')
Future<IdbFactory> deleteDatabase(String name,
- {void onBlocked(Event)}) {
+ {void onBlocked(Event e)}) {
try {
var request = _deleteDatabase(name);
if (onBlocked != null) {
request.onBlocked.listen(onBlocked);
}
- var completer = new Completer.sync();
+ var completer = new Completer<IdbFactory>.sync();
request.onSuccess.listen((e) {
completer.complete(this);
});
@@ -574,12 +574,13 @@
* Ties a request to a completer, so the completer is completed when it succeeds
* and errors out when the request errors.
*/
-Future _completeRequest(Request request) {
- var completer = new Completer.sync();
+Future/*<T>*/ _completeRequest/*<T>*/(Request request) {
+ var completer = new Completer/*<T>*/.sync();
// TODO: make sure that completer.complete is synchronous as transactions
// may be committed if the result is not processed immediately.
request.onSuccess.listen((e) {
- completer.complete(request.result);
+ var result = _cast/*<T>*/(request.result);
+ completer.complete(result);
});
request.onError.listen(completer.completeError);
return completer.future;
@@ -1075,18 +1076,18 @@
/**
* Helper for iterating over cursors in a request.
*/
- static Stream<Cursor> _cursorStreamFromResult(Request request,
+ static Stream/*<T>*/ _cursorStreamFromResult/*<T extends Cursor>*/(Request request,
bool autoAdvance) {
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController(sync: true);
+ var controller = new StreamController/*<T>*/(sync: true);
//TODO: Report stacktrace once issue 4061 is resolved.
request.onError.listen(controller.addError);
request.onSuccess.listen((e) {
- Cursor cursor = request.result;
+ var cursor = _cast/*<T>*/(request.result);
if (cursor == null) {
controller.close();
} else {
@@ -1099,6 +1100,9 @@
return controller.stream;
}
}
+
+// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
+/*=To*/ _cast/*<To>*/(dynamic x) => x;
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart
index 7104c27..2bedb48 100644
--- a/sdk/lib/internal/iterable.dart
+++ b/sdk/lib/internal/iterable.dart
@@ -304,8 +304,8 @@
if (_endOrLength != null && _endOrLength < end) end = _endOrLength;
int length = end - start;
if (length < 0) length = 0;
- List result = growable ? (new List<E>()..length = length)
- : new List<E>(length);
+ List<E> result = growable ? (new List<E>()..length = length)
+ : new List<E>(length);
for (int i = 0; i < length; i++) {
result[i] = _iterable.elementAt(start + i);
if (_iterable.length < end) throw new ConcurrentModificationError(this);
@@ -353,7 +353,7 @@
final Iterable<S> _iterable;
final _Transformation<S, T> _f;
- factory MappedIterable(Iterable iterable, T function(S value)) {
+ factory MappedIterable(Iterable<S> iterable, T function(S value)) {
if (iterable is EfficientLength) {
return new EfficientLengthMappedIterable<S, T>(iterable, function);
}
@@ -377,7 +377,7 @@
class EfficientLengthMappedIterable<S, T> extends MappedIterable<S, T>
implements EfficientLength {
- EfficientLengthMappedIterable(Iterable iterable, T function(S value))
+ EfficientLengthMappedIterable(Iterable<S> iterable, T function(S value))
: super._(iterable, function);
}
@@ -421,7 +421,7 @@
class WhereIterable<E> extends Iterable<E> {
final Iterable<E> _iterable;
- final _ElementPredicate _f;
+ final _ElementPredicate<E> _f;
WhereIterable(this._iterable, bool this._f(E element));
@@ -450,7 +450,7 @@
class ExpandIterable<S, T> extends Iterable<T> {
final Iterable<S> _iterable;
- final _ExpandFunction _f;
+ final _ExpandFunction<S, T> _f;
ExpandIterable(this._iterable, Iterable<T> this._f(S element));
@@ -459,7 +459,7 @@
class ExpandIterator<S, T> implements Iterator<T> {
final Iterator<S> _iterator;
- final _ExpandFunction _f;
+ final _ExpandFunction<S, T> _f;
// Initialize _currentExpansion to an empty iterable. A null value
// marks the end of iteration, and we don't want to call _f before
// the first moveNext call.
@@ -547,7 +547,7 @@
class TakeWhileIterable<E> extends Iterable<E> {
final Iterable<E> _iterable;
- final _ElementPredicate _f;
+ final _ElementPredicate<E> _f;
TakeWhileIterable(this._iterable, bool this._f(E element));
diff --git a/sdk/lib/internal/list.dart b/sdk/lib/internal/list.dart
index 37ee3f8..2f249f8 100644
--- a/sdk/lib/internal/list.dart
+++ b/sdk/lib/internal/list.dart
@@ -248,7 +248,7 @@
ListMapView(this._values);
- E operator[] (int key) => containsKey(key) ? _values[key] : null;
+ E operator[] (Object key) => containsKey(key) ? _values[key] : null;
int get length => _values.length;
Iterable<E> get values => new SubListIterable<E>(_values, 0, null);
@@ -257,7 +257,7 @@
bool get isEmpty => _values.isEmpty;
bool get isNotEmpty => _values.isNotEmpty;
bool containsValue(Object value) => _values.contains(value);
- bool containsKey(int key) => key is int && key >= 0 && key < length;
+ bool containsKey(Object key) => key is int && key >= 0 && key < length;
void forEach(void f(int key, E value)) {
int length = _values.length;
@@ -280,7 +280,7 @@
}
/** This operation is not supported by an unmodifiable map. */
- E remove(int key) {
+ E remove(Object key) {
throw new UnsupportedError("Cannot modify an unmodifiable map");
}
diff --git a/sdk/lib/io/bytes_builder.dart b/sdk/lib/io/bytes_builder.dart
index 610c50a..2882402 100644
--- a/sdk/lib/io/bytes_builder.dart
+++ b/sdk/lib/io/bytes_builder.dart
@@ -113,7 +113,7 @@
_length = required;
}
- void addByte(int byte) => add([byte]);
+ void addByte(int byte) { add([byte]); }
List<int> takeBytes() {
if (_buffer == null) return new Uint8List(0);
@@ -163,7 +163,7 @@
_length += bytes.length;
}
- void addByte(int byte) => add([byte]);
+ void addByte(int byte) { add([byte]); }
List<int> takeBytes() {
if (_chunks.length == 0) return new Uint8List(0);
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 620437c..d76b86d 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -252,6 +252,12 @@
}
}
+abstract class _AsyncDirectoryListerOps {
+ external factory _AsyncDirectoryListerOps(int pointer);
+
+ int getPointer();
+}
+
class _AsyncDirectoryLister {
static const int LIST_FILE = 0;
static const int LIST_DIRECTORY = 1;
@@ -269,10 +275,10 @@
final bool followLinks;
StreamController controller;
- int id;
bool canceled = false;
bool nextRunning = false;
bool closed = false;
+ _AsyncDirectoryListerOps _ops;
Completer closeCompleter = new Completer();
_AsyncDirectoryLister(this.path, this.recursive, this.followLinks) {
@@ -282,13 +288,21 @@
sync: true);
}
+ // Calling this function will increase the reference count on the native
+ // object that implements the async directory lister operations. It should
+ // only be called to pass the pointer to the IO Service, which will decrement
+ // the reference count when it is finished with it.
+ int _pointer() {
+ return (_ops == null) ? null : _ops.getPointer();
+ }
+
Stream get stream => controller.stream;
void onListen() {
_IOService._dispatch(_DIRECTORY_LIST_START, [path, recursive, followLinks])
.then((response) {
if (response is int) {
- id = response;
+ _ops = new _AsyncDirectoryListerOps(response);
next();
} else if (response is Error) {
controller.addError(response, response.stackTrace);
@@ -301,7 +315,9 @@
}
void onResume() {
- if (!nextRunning) next();
+ if (!nextRunning) {
+ next();
+ }
}
Future onCancel() {
@@ -319,11 +335,15 @@
close();
return;
}
- if (id == null) return;
- if (controller.isPaused) return;
- if (nextRunning) return;
+ if (controller.isPaused || nextRunning) {
+ return;
+ }
+ var pointer = _pointer();
+ if (pointer == null) {
+ return;
+ }
nextRunning = true;
- _IOService._dispatch(_DIRECTORY_LIST_NEXT, [id]).then((result) {
+ _IOService._dispatch(_DIRECTORY_LIST_NEXT, [pointer]).then((result) {
nextRunning = false;
if (result is List) {
next();
@@ -354,18 +374,27 @@
});
}
+ void _cleanup() {
+ controller.close();
+ closeCompleter.complete();
+ _ops = null;
+ }
+
void close() {
- if (closed) return;
- if (nextRunning) return;
- void cleanup() {
- controller.close();
- closeCompleter.complete();
+ if (closed) {
+ return;
+ }
+ if (nextRunning) {
+ return;
}
closed = true;
- if (id != null) {
- _IOService._dispatch(_DIRECTORY_LIST_STOP, [id]).whenComplete(cleanup);
+
+ var pointer = _pointer();
+ if (pointer == null) {
+ _cleanup();
} else {
- cleanup();
+ _IOService._dispatch(_DIRECTORY_LIST_STOP, [pointer])
+ .whenComplete(_cleanup);
}
}
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index d9b2cb4..4ac4486 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -751,7 +751,7 @@
* already unlocked".
*/
Future<RandomAccessFile> lock(
- [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]);
+ [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]);
/**
* Synchronously locks the file or part of the file.
@@ -784,7 +784,8 @@
* already unlocked".
*
*/
- void lockSync([FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]);
+ void lockSync(
+ [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]);
/**
* Unlocks the file or part of the file.
@@ -800,7 +801,7 @@
*
* See [lock] for more details.
*/
- Future<RandomAccessFile> unlock([int start = 0, int end]);
+ Future<RandomAccessFile> unlock([int start = 0, int end = -1]);
/**
* Synchronously unlocks the file or part of the file.
@@ -816,7 +817,7 @@
*
* See [lockSync] for more details.
*/
- void unlockSync([int start = 0, int end]);
+ void unlockSync([int start = 0, int end = -1]);
/**
* Returns a human-readable string for this RandomAccessFile instance.
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 0d0bc9e..a6fdde8 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -564,19 +564,37 @@
}
}
+abstract class _RandomAccessFileOps {
+ external factory _RandomAccessFileOps(int pointer);
-class _RandomAccessFile
- implements RandomAccessFile {
+ int getPointer();
+ int close();
+ readByte();
+ read(int bytes);
+ readInto(List<int> buffer, int start, int end);
+ writeByte(int value);
+ writeFrom(List<int> buffer, int start, int end);
+ position();
+ setPosition(int position);
+ truncate(int length);
+ length();
+ flush();
+ lock(int lock, int start, int end);
+}
+
+class _RandomAccessFile implements RandomAccessFile {
static bool _connectedResourceHandler = false;
final String path;
- int _id;
+
bool _asyncDispatched = false;
SendPort _fileService;
_FileResourceInfo _resourceInfo;
+ _RandomAccessFileOps _ops;
- _RandomAccessFile(this._id, this.path) {
+ _RandomAccessFile(int pointer, this.path) {
+ _ops = new _RandomAccessFileOps(pointer);
_resourceInfo = new _FileResourceInfo(this);
_maybeConnectHandler();
}
@@ -587,12 +605,10 @@
}
}
- external static int _getFD(int id);
-
_maybeConnectHandler() {
if (!_connectedResourceHandler) {
- // TODO(ricow): we probably need set these in some initialization code.
- // We need to make sure that these are always awailable from the
+ // TODO(ricow): We probably need to set these in some initialization code.
+ // We need to make sure that these are always available from the
// observatory even if no files (or sockets for the socket ones) are
// open.
registerExtension('ext.dart.io.getOpenFiles',
@@ -604,9 +620,9 @@
}
Future<RandomAccessFile> close() {
- return _dispatch(_FILE_CLOSE, [_id], markClosed: true).then((result) {
+ return _dispatch(_FILE_CLOSE, [null], markClosed: true).then((result) {
if (result != -1) {
- _id = result;
+ closed = closed || (result == 0);
_maybePerformCleanup();
return this;
} else {
@@ -615,20 +631,18 @@
});
}
- external static int _close(int id);
-
void closeSync() {
_checkAvailable();
- var id = _close(_id);
+ var id = _ops.close();
if (id == -1) {
throw new FileSystemException("Cannot close file", path);
}
- _id = id;
+ closed = closed || (id == 0);
_maybePerformCleanup();
}
Future<int> readByte() {
- return _dispatch(_FILE_READ_BYTE, [_id]).then((response) {
+ return _dispatch(_FILE_READ_BYTE, [null]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "readByte failed", path);
}
@@ -637,11 +651,9 @@
});
}
- external static _readByte(int id);
-
int readByteSync() {
_checkAvailable();
- var result = _readByte(_id);
+ var result = _ops.readByte();
if (result is OSError) {
throw new FileSystemException("readByte failed", path, result);
}
@@ -653,7 +665,7 @@
if (bytes is !int) {
throw new ArgumentError(bytes);
}
- return _dispatch(_FILE_READ, [_id, bytes]).then((response) {
+ return _dispatch(_FILE_READ, [null, bytes]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "read failed", path);
}
@@ -662,14 +674,12 @@
});
}
- external static _read(int id, int bytes);
-
List<int> readSync(int bytes) {
_checkAvailable();
if (bytes is !int) {
throw new ArgumentError(bytes);
}
- var result = _read(_id, bytes);
+ var result = _ops.read(bytes);
if (result is OSError) {
throw new FileSystemException("readSync failed", path, result);
}
@@ -678,15 +688,17 @@
}
Future<int> readInto(List<int> buffer, [int start = 0, int end]) {
- if (buffer is !List ||
- (start != null && start is !int) ||
- (end != null && end is !int)) {
+ if ((buffer is !List) ||
+ ((start != null) && (start is !int)) ||
+ ((end != null) && (end is !int))) {
throw new ArgumentError();
}
end = RangeError.checkValidRange(start, end, buffer.length);
- if (end == start) return new Future.value(0);
+ if (end == start) {
+ return new Future.value(0);
+ }
int length = end - start;
- return _dispatch(_FILE_READ_INTO, [_id, length]).then((response) {
+ return _dispatch(_FILE_READ_INTO, [null, length]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "readInto failed", path);
}
@@ -698,18 +710,18 @@
});
}
- external static _readInto(int id, List<int> buffer, int start, int end);
-
int readIntoSync(List<int> buffer, [int start = 0, int end]) {
_checkAvailable();
- if (buffer is !List ||
- (start != null && start is !int) ||
- (end != null && end is !int)) {
+ if ((buffer is !List) ||
+ ((start != null) && (start is !int)) ||
+ ((end != null) && (end is !int))) {
throw new ArgumentError();
}
end = RangeError.checkValidRange(start, end, buffer.length);
- if (end == start) return 0;
- var result = _readInto(_id, buffer, start, end);
+ if (end == start) {
+ return 0;
+ }
+ var result = _ops.readInto(buffer, start, end);
if (result is OSError) {
throw new FileSystemException("readInto failed", path, result);
}
@@ -721,7 +733,7 @@
if (value is !int) {
throw new ArgumentError(value);
}
- return _dispatch(_FILE_WRITE_BYTE, [_id, value]).then((response) {
+ return _dispatch(_FILE_WRITE_BYTE, [null, value]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "writeByte failed", path);
}
@@ -730,14 +742,12 @@
});
}
- external static _writeByte(int id, int value);
-
int writeByteSync(int value) {
_checkAvailable();
if (value is !int) {
throw new ArgumentError(value);
}
- var result = _writeByte(_id, value);
+ var result = _ops.writeByte(value);
if (result is OSError) {
throw new FileSystemException("writeByte failed", path, result);
}
@@ -748,12 +758,14 @@
Future<RandomAccessFile> writeFrom(
List<int> buffer, [int start = 0, int end]) {
if ((buffer is !List) ||
- (start != null && start is !int) ||
- (end != null && end is !int)) {
+ ((start != null) && (start is !int)) ||
+ ((end != null) && (end is !int))) {
throw new ArgumentError("Invalid arguments to writeFrom");
}
end = RangeError.checkValidRange(start, end, buffer.length);
- if (end == start) return new Future.value(this);
+ if (end == start) {
+ return new Future.value(this);
+ }
_BufferAndStart result;
try {
result = _ensureFastAndSerializableByteData(buffer, start, end);
@@ -762,7 +774,7 @@
}
List request = new List(4);
- request[0] = _id;
+ request[0] = null;
request[1] = result.buffer;
request[2] = result.start;
request[3] = end - (start - result.start);
@@ -775,23 +787,22 @@
});
}
- external static _writeFrom(int id, List<int> buffer, int start, int end);
-
void writeFromSync(List<int> buffer, [int start = 0, int end]) {
_checkAvailable();
- if (buffer is !List ||
- (start != null && start is !int) ||
- (end != null && end is !int)) {
+ if ((buffer is !List) ||
+ ((start != null) && (start is !int)) ||
+ ((end != null) && (end is !int))) {
throw new ArgumentError("Invalid arguments to writeFromSync");
}
end = RangeError.checkValidRange(start, end, buffer.length);
- if (end == start) return;
+ if (end == start) {
+ return;
+ }
_BufferAndStart bufferAndStart =
_ensureFastAndSerializableByteData(buffer, start, end);
- var result = _writeFrom(_id,
- bufferAndStart.buffer,
- bufferAndStart.start,
- end - (start - bufferAndStart.start));
+ var result = _ops.writeFrom(bufferAndStart.buffer,
+ bufferAndStart.start,
+ end - (start - bufferAndStart.start));
if (result is OSError) {
throw new FileSystemException("writeFrom failed", path, result);
}
@@ -816,7 +827,7 @@
}
Future<int> position() {
- return _dispatch(_FILE_POSITION, [_id]).then((response) {
+ return _dispatch(_FILE_POSITION, [null]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "position failed", path);
}
@@ -824,11 +835,9 @@
});
}
- external static _position(int id);
-
int positionSync() {
_checkAvailable();
- var result = _position(_id);
+ var result = _ops.position();
if (result is OSError) {
throw new FileSystemException("position failed", path, result);
}
@@ -836,7 +845,7 @@
}
Future<RandomAccessFile> setPosition(int position) {
- return _dispatch(_FILE_SET_POSITION, [_id, position])
+ return _dispatch(_FILE_SET_POSITION, [null, position])
.then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "setPosition failed", path);
@@ -845,18 +854,16 @@
});
}
- external static _setPosition(int id, int position);
-
void setPositionSync(int position) {
_checkAvailable();
- var result = _setPosition(_id, position);
+ var result = _ops.setPosition(position);
if (result is OSError) {
throw new FileSystemException("setPosition failed", path, result);
}
}
Future<RandomAccessFile> truncate(int length) {
- return _dispatch(_FILE_TRUNCATE, [_id, length]).then((response) {
+ return _dispatch(_FILE_TRUNCATE, [null, length]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "truncate failed", path);
}
@@ -864,18 +871,16 @@
});
}
- external static _truncate(int id, int length);
-
void truncateSync(int length) {
_checkAvailable();
- var result = _truncate(_id, length);
+ var result = _ops.truncate(length);
if (result is OSError) {
throw new FileSystemException("truncate failed", path, result);
}
}
Future<int> length() {
- return _dispatch(_FILE_LENGTH, [_id]).then((response) {
+ return _dispatch(_FILE_LENGTH, [null]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "length failed", path);
}
@@ -883,11 +888,9 @@
});
}
- external static _length(int id);
-
int lengthSync() {
_checkAvailable();
- var result = _length(_id);
+ var result = _ops.length();
if (result is OSError) {
throw new FileSystemException("length failed", path, result);
}
@@ -895,7 +898,7 @@
}
Future<RandomAccessFile> flush() {
- return _dispatch(_FILE_FLUSH, [_id]).then((response) {
+ return _dispatch(_FILE_FLUSH, [null]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"flush failed",
@@ -905,11 +908,9 @@
});
}
- external static _flush(int id);
-
void flushSync() {
_checkAvailable();
- var result = _flush(_id);
+ var result = _ops.flush();
if (result is OSError) {
throw new FileSystemException("flush failed", path, result);
}
@@ -920,19 +921,15 @@
static final int LOCK_EXCLUSIVE = 2;
Future<RandomAccessFile> lock(
- [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]) {
- if ((start != null && start is !int) ||
- (end != null && end is !int) ||
- mode is !FileLock) {
+ [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) {
+ if ((mode is !FileLock) || (start is !int) || (end is !int)) {
throw new ArgumentError();
}
- if (start == null) start = 0;
- if (end == null) end = -1;
- if (start < 0 || end < -1 || (end != -1 && start >= end)) {
+ if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
throw new ArgumentError();
}
- int lock = mode == FileLock.EXCLUSIVE ? LOCK_EXCLUSIVE : LOCK_SHARED;
- return _dispatch(_FILE_LOCK, [_id, lock, start, end])
+ int lock = (mode == FileLock.EXCLUSIVE) ? LOCK_EXCLUSIVE : LOCK_SHARED;
+ return _dispatch(_FILE_LOCK, [null, lock, start, end])
.then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, 'lock failed', path);
@@ -941,15 +938,14 @@
});
}
- Future<RandomAccessFile> unlock([int start = 0, int end]) {
- if ((start != null && start is !int) ||
- (end != null && end is !int)) {
+ Future<RandomAccessFile> unlock([int start = 0, int end = -1]) {
+ if ((start is !int) || (end is !int)) {
throw new ArgumentError();
}
- if (start == null) start = 0;
- if (end == null) end = -1;
- if (start == end) throw new ArgumentError();
- return _dispatch(_FILE_LOCK, [_id, LOCK_UNLOCK, start, end])
+ if (start == end) {
+ throw new ArgumentError();
+ }
+ return _dispatch(_FILE_LOCK, [null, LOCK_UNLOCK, start, end])
.then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, 'unlock failed', path);
@@ -958,43 +954,43 @@
});
}
- external static _lock(int id, int lock, int start, int end);
-
- void lockSync([FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]) {
+ void lockSync(
+ [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) {
_checkAvailable();
- if ((start != null && start is !int) ||
- (end != null && end is !int) ||
- mode is !FileLock) {
+ if ((mode is !FileLock) || (start is !int) || (end is !int)) {
throw new ArgumentError();
}
- if (start == null) start = 0;
- if (end == null) end = -1;
- if (start < 0 || end < -1 || (end != -1 && start >= end)) {
+ if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
throw new ArgumentError();
}
- int lock = mode == FileLock.EXCLUSIVE ? LOCK_EXCLUSIVE : LOCK_SHARED;
- var result = _lock(_id, lock, start, end);
+ int lock = (mode == FileLock.EXCLUSIVE) ? LOCK_EXCLUSIVE : LOCK_SHARED;
+ var result = _ops.lock(lock, start, end);
if (result is OSError) {
throw new FileSystemException('lock failed', path, result);
}
}
- void unlockSync([int start = 0, int end]) {
+ void unlockSync([int start = 0, int end = -1]) {
_checkAvailable();
- if ((start != null && start is !int) ||
- (end != null && end is !int)) {
+ if ((start is !int) || (end is !int)) {
throw new ArgumentError();
}
- if (start == null) start = 0;
- if (end == null) end = -1;
- if (start == end) throw new ArgumentError();
- var result = _lock(_id, LOCK_UNLOCK, start, end);
+ if (start == end) {
+ throw new ArgumentError();
+ }
+ var result = _ops.lock(LOCK_UNLOCK, start, end);
if (result is OSError) {
throw new FileSystemException('unlock failed', path, result);
}
}
- bool get closed => _id == 0;
+ bool closed = false;
+
+ // Calling this function will increase the reference count on the native
+ // object that implements the file operations. It should only be called to
+ // pass the pointer to the IO Service, which will decrement the reference
+ // count when it is finished with it.
+ int _pointer() => _ops.getPointer();
Future _dispatch(int request, List data, { bool markClosed: false }) {
if (closed) {
@@ -1005,11 +1001,12 @@
return new Future.error(new FileSystemException(msg, path));
}
if (markClosed) {
- // Set the id_ to 0 (NULL) to ensure the no more async requests
- // can be issued for this file.
- _id = 0;
+ // Set closed to true to ensure that no more async requests can be issued
+ // for this file.
+ closed = true;
}
_asyncDispatched = true;
+ data[0] = _pointer();
return _IOService._dispatch(request, data)
.whenComplete(() {
_asyncDispatched = false;
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index d002f30..846b724 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -1781,8 +1781,9 @@
_authenticate = f;
}
- void addCredentials(Uri url, String realm, HttpClientCredentials cr) =>
- _credentials.add(new _SiteCredentials(url, realm, cr));
+ void addCredentials(Uri url, String realm, HttpClientCredentials cr) {
+ _credentials.add(new _SiteCredentials(url, realm, cr));
+ }
set authenticateProxy(
Future<bool> f(String host, int port, String scheme, String realm)) {
@@ -1792,8 +1793,9 @@
void addProxyCredentials(String host,
int port,
String realm,
- HttpClientCredentials cr) =>
- _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr));
+ HttpClientCredentials cr) {
+ _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr));
+ }
set findProxy(String f(Uri uri)) => _findProxy = f;
@@ -2580,17 +2582,17 @@
_socket.encoding = value;
}
- void write(Object obj) => _socket.write(obj);
+ void write(Object obj) { _socket.write(obj); }
- void writeln([Object obj = ""]) => _socket.writeln(obj);
+ void writeln([Object obj = ""]) { _socket.writeln(obj); }
- void writeCharCode(int charCode) => _socket.writeCharCode(charCode);
+ void writeCharCode(int charCode) { _socket.writeCharCode(charCode); }
void writeAll(Iterable objects, [String separator = ""]) {
_socket.writeAll(objects, separator);
}
- void add(List<int> bytes) => _socket.add(bytes);
+ void add(List<int> bytes) { _socket.add(bytes); }
void addError(error, [StackTrace stackTrace]) =>
_socket.addError(error, stackTrace);
@@ -2599,7 +2601,7 @@
return _socket.addStream(stream);
}
- void destroy() => _socket.destroy();
+ void destroy() { _socket.destroy(); }
Future flush() => _socket.flush();
@@ -2768,11 +2770,13 @@
return "Basic $auth";
}
- void authorize(_Credentials _, HttpClientRequest request) =>
- request.headers.set(HttpHeaders.AUTHORIZATION, authorization());
+ void authorize(_Credentials _, HttpClientRequest request) {
+ request.headers.set(HttpHeaders.AUTHORIZATION, authorization());
+ }
- void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) =>
- request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, authorization());
+ void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) {
+ request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, authorization());
+ }
}
diff --git a/sdk/lib/io/http_session.dart b/sdk/lib/io/http_session.dart
index 159a54d..90075a5 100644
--- a/sdk/lib/io/http_session.dart
+++ b/sdk/lib/io/http_session.dart
@@ -53,8 +53,8 @@
putIfAbsent(key, ifAbsent) => _data.putIfAbsent(key, ifAbsent);
addAll(Map other) => _data.addAll(other);
remove(key) => _data.remove(key);
- void clear() => _data.clear();
- void forEach(void f(key, value)) => _data.forEach(f);
+ void clear() { _data.clear(); }
+ void forEach(void f(key, value)) { _data.forEach(f); }
Iterable get keys => _data.keys;
Iterable get values => _data.values;
int get length => _data.length;
@@ -104,7 +104,7 @@
_startTimer();
}
- void close() => _stopTimer();
+ void close() { _stopTimer(); }
void _bumpToEnd(_HttpSession session) {
_removeFromTimeoutQueue(session);
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index 9267084..7cea231 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.dart
@@ -54,7 +54,7 @@
// In cases where we read but did not neccesarily get any bytes, use this to
// update the readCount and timestamp. Manually update totalRead if any bytes
// where acutally read.
- void didRead() => addRead(0);
+ void didRead() { addRead(0); }
void addWrite(int bytes) {
totalWritten += bytes;
@@ -153,7 +153,7 @@
String get name => process._path;
- void stopped() => ProcessStopped(this);
+ void stopped() { ProcessStopped(this); }
Map<String, String> get fullValueMap =>
{
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index d7e722f..8c9d30c 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -109,8 +109,8 @@
other.forEach((key, value) => this[key.toUpperCase()] = value);
}
V remove(String key) => _map.remove(key.toUpperCase());
- void clear() => _map.clear();
- void forEach(void f(String key, V value)) => _map.forEach(f);
+ void clear() { _map.clear(); }
+ void forEach(void f(String key, V value)) { _map.forEach(f); }
Iterable<String> get keys => _map.keys;
Iterable<V> get values => _map.values;
int get length => _map.length;
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 07ef23e..679aa71 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -412,7 +412,6 @@
bool _filterActive = false;
_SecureFilter _secureFilter = new _SecureFilter();
- int _filterPointer;
String _selectedProtocol;
static Future<_RawSecureSocket> connect(
@@ -472,7 +471,6 @@
// Throw an ArgumentError if any field is invalid. After this, all
// errors will be reported through the future or the stream.
_secureFilter.init();
- _filterPointer = _secureFilter._pointer();
_secureFilter.registerHandshakeCompleteCallback(
_secureHandshakeCompleteHandler);
if (onBadCertificate != null) {
@@ -976,7 +974,7 @@
Future<_FilterStatus> _pushAllFilterStages() {
bool wasInHandshake = _status != CONNECTED;
List args = new List(2 + NUM_BUFFERS * 2);
- args[0] = _filterPointer;
+ args[0] = _secureFilter._pointer();
args[1] = wasInHandshake;
var bufs = _secureFilter.buffers;
for (var i = 0; i < NUM_BUFFERS; ++i) {
@@ -1201,6 +1199,10 @@
int processBuffer(int bufferIndex);
void registerBadCertificateCallback(Function callback);
void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
+
+ // This call may cause a reference counted pointer in the native
+ // implementation to be retained. It should only be called when the resulting
+ // value is passed to the IO service through a call to dispatch().
int _pointer();
List<_ExternalBuffer> get buffers;
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index 1909571..d99b05b 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.dart
@@ -48,7 +48,10 @@
* NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
* Prefer using [usePrivateKeyBytes].
*
- * iOS note: Not yet implemented.
+ * iOS note: Only PKCS12 data is supported. It should contain both the private
+ * key and the certificate chain. On iOS one call to [usePrivateKey] with this
+ * data is used instead of two calls to [useCertificateChain] and
+ * [usePrivateKey].
*/
void usePrivateKey(String file, {String password});
@@ -57,8 +60,6 @@
*
* Like [usePrivateKey], but takes the contents of the file as a list
* of bytes.
- *
- * iOS note: Not yet implemented.
*/
void usePrivateKeyBytes(List<int> keyBytes, {String password});
@@ -74,6 +75,13 @@
*
* NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
* Prefer using [setTrustedCertificatesBytes].
+ *
+ * iOS note: On iOS, this call takes only the bytes for a single DER
+ * encoded X509 certificate. It may be called multiple times to add
+ * multiple trusted certificates to the context. A DER encoded certificate
+ * can be obtained from a PEM encoded certificate by using the openssl tool:
+ *
+ * $ openssl x509 -outform der -in cert.pem -out cert.der
*/
void setTrustedCertificates(String file, {String password});
@@ -82,13 +90,6 @@
* client connections, when connecting to a secure server.
*
* Like [setTrustedCertificates] but takes the contents of the file.
- *
- * iOS note: On iOS, this call takes only the bytes for a single DER
- * encoded X509 certificate. It may be called multiple times to add
- * multiple trusted certificates to the context. A DER encoded certificate
- * can be obtained from a PEM encoded certificate by using the openssl tool:
- *
- * $ openssl x509 -outform der -in cert.pem -out cert.der
*/
void setTrustedCertificatesBytes(List<int> certBytes, {String password});
@@ -107,7 +108,8 @@
* NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
* Prefer using [useCertificateChainBytes].
*
- * iOS note: Not yet implemented.
+ * iOS note: As noted above, [usePrivateKey] does the job of both
+ * that call and this one. On iOS, this call is a no-op.
*/
void useCertificateChain(String file, {String password});
@@ -116,8 +118,6 @@
* when making secure connections, including the server certificate.
*
* Like [useCertificateChain] but takes the contents of the file.
- *
- * iOS note: Not yet implemented.
*/
void useCertificateChainBytes(List<int> chainBytes, {String password});
@@ -135,7 +135,7 @@
* NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
* Prefer using [setClientAuthoritiesBytes].
*
- * iOS note: Not yet implemented.
+ * iOS note: This call is not supported.
*/
void setClientAuthorities(String file, {String password});
@@ -145,8 +145,6 @@
* client.
*
* Like [setClientAuthority] but takes the contents of the file.
- *
- * iOS note: Not yet implemented.
*/
void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 4da5bb8..30e4eb2 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -145,8 +145,8 @@
/**
- * A [NetworkInterface] represent an active network interface on the current
- * system. It contains a list of [InternetAddress]s, that's bound to the
+ * A [NetworkInterface] represents an active network interface on the current
+ * system. It contains a list of [InternetAddress]es that are bound to the
* interface.
*/
abstract class NetworkInterface {
@@ -161,12 +161,19 @@
String get index;
/**
- * Get a list of [InternetAddress]s currently bound to this
+ * Get a list of [InternetAddress]es currently bound to this
* [NetworkInterface].
*/
List<InternetAddress> get addresses;
/**
+ * Whether [list] is supported.
+ *
+ * [list] is currently unsupported on Android.
+ */
+ external static bool get listSupported;
+
+ /**
* Query the system for [NetworkInterface]s.
*
* If [includeLoopback] is `true`, the returned list will include the
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index 9888d95..feea4ff 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -254,13 +254,14 @@
void set encoding(Encoding encoding) {
_sink.encoding = encoding;
}
- void write(object) => _sink.write(object);
- void writeln([object = "" ]) => _sink.writeln(object);
- void writeAll(objects, [sep = ""]) => _sink.writeAll(objects, sep);
- void add(List<int> data) => _sink.add(data);
- void addError(error, [StackTrace stackTrace]) =>
- _sink.addError(error, stackTrace);
- void writeCharCode(int charCode) => _sink.writeCharCode(charCode);
+ void write(object) { _sink.write(object); }
+ void writeln([object = "" ]) { _sink.writeln(object); }
+ void writeAll(objects, [sep = ""]) { _sink.writeAll(objects, sep); }
+ void add(List<int> data) { _sink.add(data); }
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
+ void writeCharCode(int charCode) { _sink.writeCharCode(charCode); }
Future addStream(Stream<List<int>> stream) => _sink.addStream(stream);
Future flush() => _sink.flush();
Future close() => _sink.close();
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 6acd661..0972e84 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -105,10 +105,11 @@
});
}
- void addError(Object error, [StackTrace stackTrace]) =>
- _eventSink.addError(error, stackTrace);
+ void addError(Object error, [StackTrace stackTrace]) {
+ _eventSink.addError(error, stackTrace);
+ }
- void close() => _eventSink.close();
+ void close() { _eventSink.close(); }
/**
* Process data received from the underlying communication channel.
@@ -677,8 +678,9 @@
addFrame(opcode, data);
}
- void addError(Object error, [StackTrace stackTrace]) =>
- _eventSink.addError(error, stackTrace);
+ void addError(Object error, [StackTrace stackTrace]) {
+ _eventSink.addError(error, stackTrace);
+ }
void close() {
int code = webSocket._outCloseCode;
@@ -1161,9 +1163,10 @@
int get closeCode => _closeCode;
String get closeReason => _closeReason;
- void add(data) => _sink.add(data);
- void addError(error, [StackTrace stackTrace]) =>
- _sink.addError(error, stackTrace);
+ void add(data) { _sink.add(data); }
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
Future addStream(Stream stream) => _sink.addStream(stream);
Future get done => _sink.done;
diff --git a/sdk/lib/js/dartium/cached_patches.dart b/sdk/lib/js/dartium/cached_patches.dart
index f6bb4ab..81edc87 100644
--- a/sdk/lib/js/dartium/cached_patches.dart
+++ b/sdk/lib/js/dartium/cached_patches.dart
@@ -3922,15 +3922,6 @@
get runtimeType => _HTMLMarqueeElement;
toString() => super.toString();
}
-patch class _MutationEvent {
- static Type get instanceRuntimeType => _MutationEventImpl;
-
-}
-class _MutationEventImpl extends _MutationEvent implements js_library.JSObjectInterfacesDom {
- _MutationEventImpl.internal_() : super.internal_();
- get runtimeType => _MutationEvent;
- toString() => super.toString();
-}
patch class _NamedNodeMap {
static Type get instanceRuntimeType => _NamedNodeMapImpl;
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 4b967b9..e15ec4f 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -4646,12 +4646,8 @@
@Experimental() // untriaged
final StyleSheet sheet;
- // Shadowing definition.
- String get title => JS("String", "#.title", this);
-
- set title(String value) {
- JS("void", "#.title = #", this, value);
- }
+ // Use implementation from Element.
+ // final String title;
@DomName('SVGStyleElement.type')
@DocsEditable()
@@ -5085,12 +5081,8 @@
// Use implementation from Element.
// final CssStyleDeclaration style;
- // Shadowing definition.
- int get tabIndex => JS("int", "#.tabIndex", this);
-
- set tabIndex(int value) {
- JS("void", "#.tabIndex = #", this, value);
- }
+ // Use implementation from Element.
+ // final int tabIndex;
@DomName('SVGElement.viewportElement')
@DocsEditable()
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 2ca320e..0be5cac 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -286,7 +286,8 @@
LibTest/typed_data/Uint8List/Uint8List.view_A05_t02: RuntimeError # co19-roll r559: Please triage this failure
LibTest/typed_data/Uint8List/Uint8List.view_A05_t03: RuntimeError # co19-roll r559: Please triage this failure
LibTest/typed_data/Uint8List/Uint8List_A02_t01: fail # co19-roll r576: Please triage this failure
-Utils/tests/Expect/identical_A01_t01: fail # co19-roll r546: Please triage this failure
+Utils/tests/Expect/identical_A01_t01: fail # co19-roll r546: Please triage this
+WebPlatformTest/DOMEvents/approved/domnodeinserted_t01: Skip # Issue 51
WebPlatformTest/Utils/test/testFail_t01: RuntimeError # co19-roll r722: Please triage this failure.
WebPlatformTest/dom/nodes/DOMImplementation-createHTMLDocument_t01: CompileTimeError # co19-roll r722: Please triage this failure.
WebPlatformTest/dom/nodes/Document-createElement_t01: CompileTimeError # co19-roll r722: Please triage this failure.
@@ -918,6 +919,7 @@
LayoutTests/fast/dom/SelectorAPI/dumpNodeList-2_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/SelectorAPI/dumpNodeList_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/StyleSheet/detached-parent-rule-without-wrapper_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/TreeWalker/TreeWalker-basic_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Window/getMatchedCSSRules-nested-rules_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/Window/getMatchedCSSRules-with-pseudo-elements-complex_t01: RuntimeError # Please triage this failure
@@ -935,6 +937,7 @@
LayoutTests/fast/dom/custom/document-register-basic_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/dom/custom/document-register-svg-extends_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/element-names_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/dom/custom/upgrade-candidate-remove-crash_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/dataset-xhtml_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/dataset_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/document-importNode-arguments_t01: RuntimeError # Please triage this failure
@@ -1469,6 +1472,9 @@
WebPlatformTest/shadow-dom/events/event-retargeting/test-001_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/events/event-retargeting/test-002_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/events/event-retargeting/test-004_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/events/events-that-are-always-stopped/test-004_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/events/events-that-are-always-stopped/test-005_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/events/events-that-are-always-stopped/test-007_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t01: Skip # Times out. Please triage this failure
WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t02: Skip # Times out. Please triage this failure
WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t05: Skip # Times out. Please triage this failure
@@ -1749,8 +1755,6 @@
LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/buffer-bind-test_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/canvas-2d-webgl-texture_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/canvas-resize-crash_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/canvas-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/canvas-zero-size_t01: RuntimeError # Please triage this failure
@@ -1759,7 +1763,6 @@
LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-lost-restored_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/css-webkit-canvas-repaint_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/css-webkit-canvas_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/draw-arrays-out-of-bounds_t01: RuntimeError # Please triage this failure
@@ -1768,23 +1771,17 @@
LayoutTests/fast/canvas/webgl/drawingbuffer-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/error-reporting_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/framebuffer-bindings-unaffected-on-resize_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/framebuffer-test_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/functions-returning-strings_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/get-active-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-bind-attrib-location-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-enable-enum-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-get-calls_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-getshadersource_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/gl-getstring_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/gl-pixelstorei_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-uniformmatrix4fv_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-vertex-attrib-zero-issues_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/gl-vertex-attrib_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/gl-vertexattribpointer_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/glsl-conformance_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/incorrect-context-object-behaviour_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/index-validation-copies-indices_t01: RuntimeError # Please triage this failure
@@ -1792,11 +1789,8 @@
LayoutTests/fast/canvas/webgl/index-validation-verifies-too-many-indices_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/index-validation-with-resized-buffer_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/index-validation_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/invalid-UTF-16_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/is-object_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/null-object-behaviour_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/null-uniform-location_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/oes-element-index-uint_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # Please triage this failure
@@ -1804,7 +1798,6 @@
LayoutTests/fast/canvas/webgl/premultiplyalpha-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/program-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/read-pixels-pack-alignment_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/renderbuffer-initialization_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/renderer-and-vendor-strings_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/shader-precision-format_t01: RuntimeError # Please triage this failure
@@ -1816,7 +1809,6 @@
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgb565_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba4444_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba5551_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba4444_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Please triage this failure
@@ -1833,7 +1825,6 @@
LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texImage2DImageDataTest_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/texture-active-bind_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texture-bindings-uneffected-on-resize_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texture-color-profile_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texture-complete_t01: RuntimeError # Please triage this failure
@@ -1849,10 +1840,8 @@
LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-exceptions_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-large-texture_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/webgl-layer-update_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-specific_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-texture-binding-preserved_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/webgl-unprefixed-context-id_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-viewport-parameters-preserved_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css-generated-content/malformed-url_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css-generated-content/pseudo-animation_t01: Pass, RuntimeError # Please triage this failure
@@ -2091,7 +2080,6 @@
LayoutTests/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-zoom-and-scroll_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-with-first-letter-style_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/CaretRangeFromPoint/hittest-relative-to-viewport_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/Document/CaretRangeFromPoint/replace-element_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/createElement-valid-names_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/createElementNS-namespace-err_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/document-title-get_t01: RuntimeError # Please triage this failure
@@ -3258,22 +3246,12 @@
LayoutTests/fast/canvas/setWidthResetAfterForcedRender_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/framebuffer-bindings-unaffected-on-resize_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/framebuffer-test_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-array-buffer-view_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgb565_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba4444_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba5551_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgb565_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba4444_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba5551_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba4444_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Please triage this failure
@@ -3283,10 +3261,7 @@
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: RuntimeError, Timeout # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: RuntimeError, Timeout # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-sub-image-2d-bad-args_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-sub-image-2d_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texture-transparent-pixels-initialized_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/uniform-location_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/uninitialized-test_t01: RuntimeError # Please triage this failure
@@ -3499,6 +3474,7 @@
LayoutTests/fast/dom/Range/mutation_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Range/range-comparePoint_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Range/range-constructor_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/Range/range-created-during-remove-children_t01: RuntimeError
LayoutTests/fast/dom/Range/range-detached-exceptions_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Range/range-exceptions_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Range/range-expand_t01: RuntimeError # Please triage this failure
@@ -3763,6 +3739,8 @@
LayoutTests/fast/forms/plaintext-mode-1_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/search-popup-crasher_t01: Pass, RuntimeError # Fails on 7.1. Please triage this failure
LayoutTests/fast/forms/selection-wrongtype_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/forms/select-set-length-with-mutation-remove_t01: RuntimeError
+LayoutTests/fast/forms/select-set-length-with-mutation-reparent_t01: RuntimeError
LayoutTests/fast/forms/setrangetext_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/textarea-maxlength_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/textarea-paste-newline_t01: RuntimeError # Please triage this failure
@@ -8150,7 +8128,6 @@
LayoutTests/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-zoom-and-scroll_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-with-first-letter-style_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/CaretRangeFromPoint/hittest-relative-to-viewport_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/Document/CaretRangeFromPoint/replace-element_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/createElement-valid-names_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Document/createElementNS-namespace-err_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/Element/attribute-uppercase_t01: RuntimeError # Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index b788b84..1436313 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -203,7 +203,6 @@
Language/Libraries_and_Scripts/URIs/syntax_t10: RuntimeError # Please triage this failure.
Language/Libraries_and_Scripts/URIs/syntax_t14: RuntimeError # Please triage this failure.
Language/Libraries_and_Scripts/URIs/syntax_t15: RuntimeError # Please triage this failure.
-Language/Metadata/before_param_t09: RuntimeError # Issue 26187
Language/Metadata/before_variable_t01: RuntimeError # Please triage this failure.
Language/Mixins/Mixin_Application/error_t01: Fail # co19 issue 43
Language/Mixins/Mixin_Application/error_t02: Fail # co19 issue 43
@@ -1383,4 +1382,3 @@
LibTest/html/Element/insertBefore_A01_t01: RuntimeError # Issue 26134
LibTest/html/Element/insertAllBefore_A01_t01: RuntimeError # Issue 26134
LibTest/html/CanvasRenderingContext2D/addEventListener_A01_t06: Skip # Issue 26134, timeout
-html/cross_domain_iframe_test: RuntimeError # Issue 26134
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 57ac699..59ebaf3 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -163,3 +163,8 @@
LibTest/typed_data/Uint64List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
LibTest/typed_data/Uint8ClampedList/runtimeType_A01_t01: Fail,OK # Expects exact type name.
LibTest/typed_data/Uint8List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
+
+[ ($arch == simdbc || $arch == simdbc64) && $mode == debug ]
+# TODO(vegorov) These tests are very slow on unoptimized SIMDBC
+LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout
+LibTest/collection/ListBase/ListBase_class_A01_t02: Timeout
diff --git a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
index e774726..7f531eb 100644
--- a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
+++ b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
@@ -94,7 +94,7 @@
}
void analyze(ResolvedAst resolvedAst) {
- if (resolvedAst.node == null) {
+ if (resolvedAst.kind != ResolvedAstKind.PARSED) {
// Skip synthesized members.
return;
}
diff --git a/tests/compiler/dart2js/analyze_test_test.dart b/tests/compiler/dart2js/analyze_test_test.dart
index 5da181c..93cf7b9 100644
--- a/tests/compiler/dart2js/analyze_test_test.dart
+++ b/tests/compiler/dart2js/analyze_test_test.dart
@@ -49,6 +49,8 @@
"backend_dart/",
// Broken tests:
"http_test.dart",
+ // Package directory
+ "packages/",
];
const List<MessageKind> MESSAGE_SKIP_LIST = const <MessageKind>[
diff --git a/tests/compiler/dart2js/compiler_test.dart b/tests/compiler/dart2js/compiler_test.dart
index 691b86b..3e595c8 100644
--- a/tests/compiler/dart2js/compiler_test.dart
+++ b/tests/compiler/dart2js/compiler_test.dart
@@ -3,64 +3,27 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:async";
-import "package:expect/expect.dart";
+
import "package:async_helper/async_helper.dart";
+import 'package:compiler/compiler.dart';
import "package:compiler/src/elements/elements.dart";
-import "package:compiler/src/resolution/members.dart";
-import "package:compiler/src/diagnostics/diagnostic_listener.dart";
+import "package:expect/expect.dart";
+
import "mock_compiler.dart";
-import "diagnostic_reporter_helper.dart";
-
-
-class CallbackMockCompiler extends MockCompiler {
- CallbackReporter reporter;
-
- CallbackMockCompiler() : super.internal() {
- reporter = new CallbackReporter(super.reporter);
- }
-
-}
-
-class CallbackReporter extends DiagnosticReporterWrapper {
- final DiagnosticReporter reporter;
-
- CallbackReporter(this.reporter);
-
- var onError;
- var onWarning;
-
- setOnError(var f) => onError = f;
- setOnWarning(var f) => onWarning = f;
-
- void reportWarning(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- if (onWarning != null) {
- onWarning(this, message.spannable, message.message);
- }
- super.reportWarning(message, infos);
- }
-
- void reportError(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- if (onError != null) {
- onError(this, message.spannable, message.message);
- }
- super.reportError(message, infos);
- }
-}
Future testErrorHandling() {
// Test that compiler.currentElement is set correctly when
// reporting errors/warnings.
- CallbackMockCompiler compiler = new CallbackMockCompiler();
+ MockCompiler compiler = new MockCompiler.internal();
return compiler.init().then((_) {
- ResolverVisitor visitor = compiler.resolverVisitor();
compiler.parseScript('NoSuchPrefix.NoSuchType foo() {}');
FunctionElement foo = compiler.mainApp.find('foo');
- compiler.reporter.setOnWarning(
- (c, n, m) => Expect.equals(foo, compiler.currentElement));
+ compiler.diagnosticHandler =
+ (Uri uri, int begin, int end, String message, Diagnostic kind) {
+ if (kind == Diagnostic.WARNING) {
+ Expect.equals(foo, compiler.currentElement);
+ }
+ };
foo.computeType(compiler.resolution);
Expect.equals(1, compiler.diagnosticCollector.warnings.length);
});
diff --git a/tests/compiler/dart2js/diagnostic_helper.dart b/tests/compiler/dart2js/diagnostic_helper.dart
index c9b19e1..d87579f 100644
--- a/tests/compiler/dart2js/diagnostic_helper.dart
+++ b/tests/compiler/dart2js/diagnostic_helper.dart
@@ -36,11 +36,6 @@
class DiagnosticCollector implements CompilerDiagnostics {
List<CollectedMessage> messages = <CollectedMessage>[];
- void call(Uri uri, int begin, int end, String message, Diagnostic kind) {
- throw '';
- report(null, uri, begin, end, message, kind);
- }
-
@override
void report(Message message,
Uri uri, int begin, int end, String text, Diagnostic kind) {
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 715d4d6..b67b026 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -37,7 +37,7 @@
final String testMarker;
final String testType;
final Function onTest;
- DiagnosticReporter reporter;
+ TestDiagnosticReporter reporter;
TestCompiler(api.CompilerInput inputProvider,
api.CompilerOutput outputProvider,
@@ -51,7 +51,8 @@
String this.testMarker,
String this.testType,
Function this.onTest)
- : super(inputProvider, outputProvider, handler,
+ : reporter = new TestDiagnosticReporter(),
+ super(inputProvider, outputProvider, handler,
new CompilerOptions.parse(
libraryRoot: libraryRoot,
packageRoot: packageRoot,
@@ -59,7 +60,8 @@
environment: environment,
packageConfig: packageConfig,
packagesDiscoveryProvider: findPackages)) {
- reporter = new TestDiagnosticReporter(this, super.reporter);
+ reporter.compiler = this;
+ reporter.reporter = super.reporter;
test('Compiler');
}
@@ -136,10 +138,8 @@
}
class TestDiagnosticReporter extends DiagnosticReporterWrapper {
- final TestCompiler compiler;
- final DiagnosticReporter reporter;
-
- TestDiagnosticReporter(this.compiler, this.reporter);
+ TestCompiler compiler;
+ DiagnosticReporter reporter;
@override
withCurrentElement(Element element, f()) {
diff --git a/tests/compiler/dart2js/find_my_name_test.dart b/tests/compiler/dart2js/find_my_name_test.dart
index dd93af3..3c5c22b 100644
--- a/tests/compiler/dart2js/find_my_name_test.dart
+++ b/tests/compiler/dart2js/find_my_name_test.dart
@@ -36,7 +36,7 @@
testClass(String code, MockCompiler compiler) {
int skip = code.indexOf('{');
ClassElementX cls = parseUnit(code, compiler, compiler.mainApp).head;
- cls.parseNode(compiler.parsing);
+ cls.parseNode(compiler.parsingContext);
cls.forEachLocalMember((Element e) {
String name = e.name;
if (e.isConstructor) {
diff --git a/tests/compiler/dart2js/library_resolution_test.dart b/tests/compiler/dart2js/library_resolution_test.dart
index c5a5fa7..93a039e 100644
--- a/tests/compiler/dart2js/library_resolution_test.dart
+++ b/tests/compiler/dart2js/library_resolution_test.dart
@@ -37,12 +37,6 @@
new CompilerOptions(
libraryRoot: libraryRoot,
packageRoot: packageRoot));
-
- Uri lookupLibraryUri(String libraryName) {
- if (libraryName == "m_o_c_k_1") return mock1LibraryUri;
- if (libraryName == "m_o_c_k_2") return mock2LibraryUri;
- return super.lookupLibraryUri(libraryName);
- }
}
main() async {
@@ -87,6 +81,9 @@
asyncStart();
await compiler.setupSdk();
+ // TODO(het): Find cleaner way to do this
+ compiler.resolvedUriTranslator.sdkLibraries['m_o_c_k_1'] = mock1LibraryUri;
+ compiler.resolvedUriTranslator.sdkLibraries['m_o_c_k_2'] = mock2LibraryUri;
var library =
await compiler.libraryLoader.loadLibrary(Uri.parse("dart:m_o_c_k_1"));
await checkLibrary(library);
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 7c88613..47c1a43 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -181,15 +181,10 @@
compiler.backend.constantCompilerTask.copyConstantValues(
cachedCompiler.backend.constantCompilerTask);
- compiler.symbolConstructor = cachedCompiler.symbolConstructor;
compiler.mirrorSystemClass = cachedCompiler.mirrorSystemClass;
compiler.mirrorsUsedClass = cachedCompiler.mirrorsUsedClass;
compiler.mirrorSystemGetNameFunction =
cachedCompiler.mirrorSystemGetNameFunction;
- compiler.symbolImplementationClass =
- cachedCompiler.symbolImplementationClass;
- compiler.symbolValidatedConstructor =
- cachedCompiler.symbolValidatedConstructor;
compiler.mirrorsUsedConstructor = cachedCompiler.mirrorsUsedConstructor;
compiler.deferredLibraryClass = cachedCompiler.deferredLibraryClass;
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index e2628b8..839c083 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -27,6 +27,7 @@
import 'package:compiler/src/resolution/registry.dart';
import 'package:compiler/src/resolution/scope.dart';
import 'package:compiler/src/resolution/tree_elements.dart';
+import 'package:compiler/src/resolved_uri_translator.dart';
import 'package:compiler/src/script.dart';
import 'package:compiler/src/tree/tree.dart';
import 'package:compiler/src/old_to_new_api.dart';
@@ -65,6 +66,8 @@
final String testedPatchVersion;
final LibrarySourceProvider librariesOverride;
final DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
+ final ResolvedUriTranslator resolvedUriTranslator =
+ new MockResolvedUriTranslator();
MockCompiler.internal(
{Map<String, String> coreSource,
@@ -257,9 +260,6 @@
return new Future.value();
}
- Uri translateResolvedUri(LibraryElement importingLibrary,
- Uri resolvedUri, Spannable spannable) => resolvedUri;
-
// The mock library doesn't need any patches.
Uri resolvePatchUri(String dartLibraryName) {
if (dartLibraryName == 'core') {
@@ -288,6 +288,17 @@
}
}
+class MockResolvedUriTranslator implements ResolvedUriTranslator {
+ static final _emptySet = new Set();
+
+ Uri translate(LibraryElement importingLibrary, Uri resolvedUri,
+ [Spannable spannable]) =>
+ resolvedUri;
+ Set<Uri> get disallowedLibraryUris => _emptySet;
+ bool get mockableLibraryUsed => false;
+ Map<String, Uri> get sdkLibraries => const <String, Uri>{};
+}
+
class CollectingTreeElements extends TreeElementMapping {
final Map<Node, Element> map = new LinkedHashMap<Node, Element>();
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index 028fa06..13556b7 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -124,7 +124,7 @@
ElementX element = parseUnit(text, compiler, compiler.mainApp).head;
Expect.isNotNull(element);
Expect.equals(ElementKind.FUNCTION, element.kind);
- return element.parseNode(compiler.parsing);
+ return element.parseNode(compiler.parsingContext);
}
Node parseMember(String text, {DiagnosticReporter reporter}) {
@@ -153,7 +153,7 @@
var unit = new CompilationUnitElementX(script, library);
DiagnosticReporter reporter = compiler.reporter;
ElementListener listener = new ElementListener(
- compiler.parsing.getScannerOptionsFor(library),
+ compiler.parsingContext.getScannerOptionsFor(library),
reporter, unit, new IdGenerator());
PartialParser parser = new PartialParser(listener, new MockParserOptions());
reporter.withCurrentElement(unit, () => parser.parseUnit(tokens));
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 3581b17..00ef722 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -45,7 +45,7 @@
}
void expectHasBody(compiler, ElementX element) {
- var node = element.parseNode(compiler.parsing);
+ var node = element.parseNode(compiler.parsingContext);
Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
Expect.isNotNull(node.body);
// If the element has a body it is either a Block or a Return statement,
@@ -55,7 +55,7 @@
}
void expectHasNoBody(compiler, ElementX element) {
- var node = element.parseNode(compiler.parsing);
+ var node = element.parseNode(compiler.parsingContext);
Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
Expect.isFalse(node.hasBody);
}
@@ -336,7 +336,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -366,7 +366,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
ensure(compiler,
"field",
container.lookupLocalMember,
@@ -400,7 +400,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -429,7 +429,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -458,7 +458,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
expectIsPatch: true);
@@ -555,7 +555,7 @@
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
container.ensureResolved(compiler.resolution);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
DiagnosticCollector collector = compiler.diagnosticCollector;
void expect(String methodName, List infos, List errors) {
@@ -635,7 +635,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
DiagnosticCollector collector = compiler.diagnosticCollector;
collector.clear();
compiler.resolver.resolveMethodElement(
@@ -696,7 +696,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isTrue(collector.warnings.isEmpty,
@@ -784,7 +784,7 @@
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
expectIsPatched: true);
- container.parseNode(compiler.parsing);
+ container.parseNode(compiler.parsingContext);
DiagnosticCollector collector = compiler.diagnosticCollector;
print('testPatchNonExternalMember.errors:${collector.errors}');
diff --git a/tests/compiler/dart2js/related_types.dart b/tests/compiler/dart2js/related_types.dart
index 12b60c5..d3f04e3 100644
--- a/tests/compiler/dart2js/related_types.dart
+++ b/tests/compiler/dart2js/related_types.dart
@@ -59,9 +59,9 @@
if (!compiler.resolution.hasBeenResolved(member)) return;
ResolvedAst resolvedAst = member.resolvedAst;
- RelatedTypesChecker relatedTypesChecker =
- new RelatedTypesChecker(compiler, resolvedAst);
- if (resolvedAst.node != null) {
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ RelatedTypesChecker relatedTypesChecker =
+ new RelatedTypesChecker(compiler, resolvedAst);
compiler.reporter.withCurrentElement(member.implementation, () {
relatedTypesChecker.apply(resolvedAst.node);
});
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index a69ce72..f8fb479 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -227,7 +227,7 @@
new ResolutionRegistry(compiler,
new CollectingTreeElements(fooB)));
FunctionExpression node =
- (fooB as FunctionElementX).parseNode(compiler.parsing);
+ (fooB as FunctionElementX).parseNode(compiler.parsingContext);
visitor.visit(node.body);
Map mapping = map(visitor);
@@ -271,7 +271,7 @@
new ResolutionRegistry(compiler,
new CollectingTreeElements(funElement)));
FunctionExpression function =
- (funElement as FunctionElementX).parseNode(compiler.parsing);
+ (funElement as FunctionElementX).parseNode(compiler.parsingContext);
visitor.visit(function.body);
Map mapping = map(visitor);
List<Element> values = mapping.values.toList();
@@ -296,7 +296,7 @@
new ResolutionRegistry(compiler,
new CollectingTreeElements(funElement)));
FunctionExpression function =
- (funElement as FunctionElementX).parseNode(compiler.parsing);
+ (funElement as FunctionElementX).parseNode(compiler.parsingContext);
visitor.visit(function.body);
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.equals(0, collector.warnings.length);
@@ -665,7 +665,7 @@
VariableElementX element = compiler.mainApp.find("a");
Expect.equals(ElementKind.FIELD, element.kind);
VariableDefinitions node =
- element.variables.parseNode(element, compiler.parsing);
+ element.variables.parseNode(element, compiler.parsingContext);
Identifier typeName = node.type.typeName;
Expect.equals(typeName.source, 'int');
@@ -677,9 +677,9 @@
Expect.isTrue(bElement != cElement);
VariableDefinitions bNode =
- bElement.variables.parseNode(bElement, compiler.parsing);
+ bElement.variables.parseNode(bElement, compiler.parsingContext);
VariableDefinitions cNode =
- cElement.variables.parseNode(cElement, compiler.parsing);
+ cElement.variables.parseNode(cElement, compiler.parsingContext);
Expect.equals(bNode, cNode);
Expect.isNull(bNode.type);
Expect.isTrue(bNode.modifiers.isVar);
diff --git a/tests/compiler/dart2js/serialization_compilation_test.dart b/tests/compiler/dart2js/serialization_compilation_test.dart
new file mode 100644
index 0000000..590f57a
--- /dev/null
+++ b/tests/compiler/dart2js/serialization_compilation_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2016, 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.serialization_compilation_test;
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/common/backend_api.dart';
+import 'package:compiler/src/common/names.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/filenames.dart';
+import 'memory_compiler.dart';
+import 'serialization_helper.dart';
+import 'serialization_test_data.dart';
+import 'output_collector.dart';
+
+main(List<String> args) {
+ asyncTest(() async {
+ Arguments arguments = new Arguments.from(args);
+ String serializedData = await serializeDartCore(
+ arguments: arguments,
+ serializeResolvedAst: true);
+ if (arguments.filename != null) {
+ Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
+ await compile(serializedData, entryPoint, null);
+ } else {
+ Uri entryPoint = Uri.parse('memory:main.dart');
+ // TODO(johnniwinther): Handle the remaining tests.
+ for (Test test in TESTS.sublist(0, 1)) {
+ await compile(serializedData, entryPoint, test,
+ verbose: arguments.verbose);
+ }
+ }
+ });
+}
+
+Future compile(String serializedData, Uri entryPoint, Test test,
+ {bool verbose: false}) async {
+ String testDescription =
+ test != null ? test.sourceFiles[entryPoint.path] : '${entryPoint}';
+ print('------------------------------------------------------------------');
+ print('compile ${testDescription}');
+ print('------------------------------------------------------------------');
+ OutputCollector outputCollector = new OutputCollector();
+ await runCompiler(
+ entryPoint: entryPoint,
+ memorySourceFiles: test != null ? test.sourceFiles : const {},
+ options: [Flags.disableTypeInference,
+ Flags.disableInlining],
+ outputProvider: outputCollector,
+ beforeRun: (Compiler compiler) {
+ deserialize(compiler, serializedData, deserializeResolvedAst: true);
+ });
+ if (verbose) {
+ print(outputCollector.getOutput('', 'js'));
+ }
+}
+
diff --git a/tests/compiler/dart2js/serialization_helper.dart b/tests/compiler/dart2js/serialization_helper.dart
index c863265..2d1ea1f 100644
--- a/tests/compiler/dart2js/serialization_helper.dart
+++ b/tests/compiler/dart2js/serialization_helper.dart
@@ -5,41 +5,95 @@
library dart2js.serialization_helper;
import 'dart:async';
-import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
-import 'package:compiler/compiler_new.dart';
+import 'dart:io';
+
import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/common.dart';
import 'package:compiler/src/common/backend_api.dart';
import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/common/resolution.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/filenames.dart';
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/scanner/scanner.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
+import 'package:compiler/src/script.dart';
import 'package:compiler/src/serialization/impact_serialization.dart';
import 'package:compiler/src/serialization/json_serializer.dart';
+import 'package:compiler/src/serialization/modelz.dart';
import 'package:compiler/src/serialization/resolved_ast_serialization.dart';
import 'package:compiler/src/serialization/serialization.dart';
-import 'package:compiler/src/serialization/modelz.dart';
import 'package:compiler/src/serialization/task.dart';
import 'package:compiler/src/tokens/token.dart';
-import 'package:compiler/src/script.dart';
+import 'package:compiler/src/universe/call_structure.dart';
import 'package:compiler/src/universe/world_impact.dart';
+import 'package:compiler/src/universe/use.dart';
+
import 'memory_compiler.dart';
+class Arguments {
+ final String filename;
+ final bool loadSerializedData;
+ final bool saveSerializedData;
+ final String serializedDataFileName;
+ final bool verbose;
-Future<String> serializeDartCore({bool serializeResolvedAst: false}) async {
- Compiler compiler = compilerFor(
- options: [Flags.analyzeAll]);
- compiler.serialization.supportSerialization = true;
- await compiler.run(Uris.dart_core);
- return serialize(
- compiler,
- compiler.libraryLoader.libraries,
- serializeResolvedAst: serializeResolvedAst)
- .toText(const JsonSerializationEncoder());
+ const Arguments({
+ this.filename,
+ this.loadSerializedData: false,
+ this.saveSerializedData: false,
+ this.serializedDataFileName: 'out.data',
+ this.verbose: false});
+
+ factory Arguments.from(List<String> arguments) {
+ String filename;
+ for (String arg in arguments) {
+ if (!arg.startsWith('-')) {
+ filename = arg;
+ }
+ }
+ bool verbose = arguments.contains('-v');
+ bool loadSerializedData = arguments.contains('-l');
+ bool saveSerializedData = arguments.contains('-s');
+ return new Arguments(
+ filename: filename,
+ verbose: verbose,
+ loadSerializedData: loadSerializedData,
+ saveSerializedData: saveSerializedData);
+ }
+}
+
+
+Future<String> serializeDartCore(
+ {Arguments arguments: const Arguments(),
+ bool serializeResolvedAst: false}) async {
+ print('------------------------------------------------------------------');
+ print('serialize dart:core');
+ print('------------------------------------------------------------------');
+ String serializedData;
+ if (arguments.loadSerializedData) {
+ File file = new File(arguments.serializedDataFileName);
+ if (file.existsSync()) {
+ print('Loading data from $file');
+ serializedData = file.readAsStringSync();
+ }
+ }
+ if (serializedData == null) {
+ Compiler compiler = compilerFor(
+ options: [Flags.analyzeAll]);
+ compiler.serialization.supportSerialization = true;
+ await compiler.run(Uris.dart_core);
+ serializedData = serialize(
+ compiler,
+ compiler.libraryLoader.libraries,
+ serializeResolvedAst: serializeResolvedAst)
+ .toText(const JsonSerializationEncoder());
+ if (arguments.saveSerializedData) {
+ File file = new File(arguments.serializedDataFileName);
+ print('Saving data to $file');
+ file.writeAsStringSync(serializedData);
+ }
+ }
+ return serializedData;
}
Serializer serialize(
@@ -53,7 +107,7 @@
serializer.plugins.add(new ResolutionImpactSerializer(compiler.resolution));
if (serializeResolvedAst) {
serializer.plugins.add(
- new ResolvedAstSerializerPlugin(compiler.resolution));
+ new ResolvedAstSerializerPlugin(compiler.resolution, compiler.backend));
}
for (LibraryElement library in libraries) {
@@ -91,7 +145,7 @@
if (resolution.hasBeenResolved(element)) {
ResolutionImpact impact = resolution.getResolutionImpact(element);
ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
- new ImpactSerializer(encoder).serialize(impact);
+ new ImpactSerializer(element, encoder).serialize(impact);
}
}
}
@@ -103,7 +157,8 @@
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG);
if (decoder != null) {
- impactMap[element] = ImpactDeserializer.deserializeImpact(decoder);
+ impactMap[element] =
+ ImpactDeserializer.deserializeImpact(element, decoder);
}
}
}
@@ -126,7 +181,8 @@
: this._compiler = compiler,
this._deserializeResolvedAst = deserializeResolvedAst,
this._resolvedAstDeserializer = deserializeResolvedAst
- ? new ResolvedAstDeserializerPlugin(compiler.parsing) : null {
+ ? new ResolvedAstDeserializerPlugin(
+ compiler.parsingContext, compiler.backend) : null {
_deserializer.plugins.add(_resolutionImpactDeserializer);
if (_deserializeResolvedAst) {
_deserializer.plugins.add(_resolvedAstDeserializer);
@@ -141,9 +197,10 @@
if (_deserializeResolvedAst) {
return Future.forEach(library.compilationUnits,
(CompilationUnitElement compilationUnit) {
- Script script = compilationUnit.script;
+ ScriptZ script = compilationUnit.script;
return _compiler.readScript(script.readableUri)
.then((Script newScript) {
+ script.file = newScript.file;
_resolvedAstDeserializer.sourceFiles[script.resourceUri] =
newScript.file;
});
@@ -154,6 +211,14 @@
}
@override
+ bool hasResolvedAst(Element element) {
+ if (_resolvedAstDeserializer != null) {
+ return _resolvedAstDeserializer.hasResolvedAst(element);
+ }
+ return false;
+ }
+
+ @override
ResolvedAst getResolvedAst(Element element) {
if (_resolvedAstDeserializer != null) {
return _resolvedAstDeserializer.getResolvedAst(element);
@@ -162,19 +227,41 @@
}
@override
+ bool hasResolutionImpact(Element element) {
+ if (element.isConstructor &&
+ element.enclosingClass.isUnnamedMixinApplication) {
+ return true;
+ }
+ return _resolutionImpactDeserializer.impactMap.containsKey(element);
+ }
+
+ @override
ResolutionImpact getResolutionImpact(Element element) {
+ if (element.isConstructor &&
+ element.enclosingClass.isUnnamedMixinApplication) {
+ ClassElement superclass = element.enclosingClass.superclass;
+ ConstructorElement superclassConstructor =
+ superclass.lookupConstructor(element.name);
+ assert(invariant(element, superclassConstructor != null,
+ message: "Superclass constructor '${element.name}' called from "
+ "${element} not found in ${superclass}."));
+ // TODO(johnniwinther): Compute callStructure. Currently not used.
+ CallStructure callStructure;
+ return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () {
+ return new DeserializedResolutionImpact(
+ staticUses: <StaticUse>[new StaticUse.superConstructorInvoke(
+ superclassConstructor, callStructure)]);
+ });
+ }
return _resolutionImpactDeserializer.impactMap[element];
}
@override
WorldImpact computeWorldImpact(Element element) {
ResolutionImpact resolutionImpact = getResolutionImpact(element);
- if (resolutionImpact == null) {
- print('No impact found for $element (${element.library})');
- return const WorldImpact();
- } else {
- return _impactTransformer.transformResolutionImpact(resolutionImpact);
- }
+ assert(invariant(element, resolutionImpact != null,
+ message: 'No impact found for $element (${element.library})'));
+ return _impactTransformer.transformResolutionImpact(resolutionImpact);
}
@override
@@ -187,28 +274,42 @@
class ResolvedAstSerializerPlugin extends SerializerPlugin {
final Resolution resolution;
+ final Backend backend;
- ResolvedAstSerializerPlugin(this.resolution);
+ ResolvedAstSerializerPlugin(this.resolution, this.backend);
@override
void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
- if (element is MemberElement && resolution.hasResolvedAst(element)) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration"));
+ if (element is MemberElement) {
+ assert(invariant(element, resolution.hasResolvedAst(element),
+ message: "Element $element must have a resolved ast"));
ResolvedAst resolvedAst = resolution.getResolvedAst(element);
ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG);
- new ResolvedAstSerializer(objectEncoder, resolvedAst).serialize();
+ new ResolvedAstSerializer(
+ objectEncoder,
+ resolvedAst,
+ backend.serialization.serializer).serialize();
}
}
}
class ResolvedAstDeserializerPlugin extends DeserializerPlugin {
- final Parsing parsing;
+ final ParsingContext parsingContext;
+ final Backend backend;
final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
Map<Element, ResolvedAst> _resolvedAstMap = <Element, ResolvedAst>{};
Map<Element, ObjectDecoder> _decoderMap = <Element, ObjectDecoder>{};
Map<Uri, Token> beginTokenMap = <Uri, Token>{};
- ResolvedAstDeserializerPlugin(this.parsing);
+ ResolvedAstDeserializerPlugin(this.parsingContext, this.backend);
+
+ bool hasResolvedAst(Element element) {
+ return _resolvedAstMap.containsKey(element) ||
+ _decoderMap.containsKey(element);
+ }
ResolvedAst getResolvedAst(Element element) {
ResolvedAst resolvedAst = _resolvedAstMap[element];
@@ -217,7 +318,8 @@
if (decoder != null) {
resolvedAst = _resolvedAstMap[element] =
ResolvedAstDeserializer.deserialize(
- element, decoder, parsing, findToken);
+ element, decoder, parsingContext, findToken,
+ backend.serialization.deserializer);
_decoderMap.remove(element);
}
}
diff --git a/tests/compiler/dart2js/serialization_impact_test.dart b/tests/compiler/dart2js/serialization_impact_test.dart
index 05d91d6..6f5fd15 100644
--- a/tests/compiler/dart2js/serialization_impact_test.dart
+++ b/tests/compiler/dart2js/serialization_impact_test.dart
@@ -16,15 +16,18 @@
import 'serialization_helper.dart';
import 'serialization_test_helper.dart';
-main(List<String> arguments) {
+main(List<String> args) {
+ Arguments arguments = new Arguments.from(args);
asyncTest(() async {
- String serializedData = await serializeDartCore();
- if (arguments.isNotEmpty) {
- Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.last));
+ String serializedData = await serializeDartCore(arguments: arguments);
+ if (arguments.filename != null) {
+ Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
await check(serializedData, entryPoint);
} else {
Uri entryPoint = Uri.parse('memory:main.dart');
- await check(serializedData, entryPoint, {'main.dart': 'main() {}'});
+ await check(serializedData, entryPoint,
+ sourceFiles: {'main.dart': 'main() {}'},
+ verbose: arguments.verbose);
}
});
}
@@ -32,20 +35,21 @@
Future check(
String serializedData,
Uri entryPoint,
- [Map<String, String> sourceFiles = const <String, String>{}]) async {
+ {Map<String, String> sourceFiles: const <String, String>{},
+ bool verbose: false}) async {
Compiler compilerNormal = compilerFor(
memorySourceFiles: sourceFiles,
- options: [Flags.analyzeOnly]);
+ options: [Flags.analyzeAll]);
compilerNormal.resolution.retainCachesForTesting = true;
await compilerNormal.run(entryPoint);
Compiler compilerDeserialized = compilerFor(
memorySourceFiles: sourceFiles,
- options: [Flags.analyzeOnly]);
+ options: [Flags.analyzeAll]);
compilerDeserialized.resolution.retainCachesForTesting = true;
deserialize(compilerDeserialized, serializedData);
await compilerDeserialized.run(entryPoint);
- checkAllImpacts(compilerNormal, compilerDeserialized, verbose: true);
+ checkAllImpacts(compilerNormal, compilerDeserialized, verbose: verbose);
}
diff --git a/tests/compiler/dart2js/serialization_model_test.dart b/tests/compiler/dart2js/serialization_model_test.dart
index 0e5363f..52547ae 100644
--- a/tests/compiler/dart2js/serialization_model_test.dart
+++ b/tests/compiler/dart2js/serialization_model_test.dart
@@ -30,52 +30,23 @@
import 'serialization_test_data.dart';
import 'serialization_test_helper.dart';
-main(List<String> arguments) {
- String filename;
- for (String arg in arguments) {
- if (!arg.startsWith('-')) {
- filename = arg;
- }
- }
- bool verbose = arguments.contains('-v');
-
+main(List<String> args) {
asyncTest(() async {
- print('------------------------------------------------------------------');
- print('serialize dart:core');
- print('------------------------------------------------------------------');
- String serializedData;
- File file = new File('out.data');
- if (arguments.contains('-l')) {
- if (file.existsSync()) {
- print('Loading data from $file');
- serializedData = file.readAsStringSync();
- }
- }
- if (serializedData == null) {
- serializedData = await serializeDartCore();
- if (arguments.contains('-s')) {
- print('Saving data to $file');
- file.writeAsStringSync(serializedData);
- }
- }
- if (filename != null) {
- Uri entryPoint = Uri.base.resolve(nativeToUriPath(filename));
+ Arguments arguments = new Arguments.from(args);
+ String serializedData = await serializeDartCore(arguments: arguments);
+ if (arguments.filename != null) {
+ Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
await check(serializedData, entryPoint);
} else {
Uri entryPoint = Uri.parse('memory:main.dart');
for (Test test in TESTS) {
- if (test.sourceFiles['main.dart']
- .contains('main(List<String> arguments)')) {
- // TODO(johnniwinther): Check this test.
- continue;
- }
print('==============================================================');
print(test.sourceFiles);
await check(
serializedData,
entryPoint,
sourceFiles: test.sourceFiles,
- verbose: verbose);
+ verbose: arguments.verbose);
}
}
});
diff --git a/tests/compiler/dart2js/serialization_resolved_ast_test.dart b/tests/compiler/dart2js/serialization_resolved_ast_test.dart
index af5d8a3..7712f9a 100644
--- a/tests/compiler/dart2js/serialization_resolved_ast_test.dart
+++ b/tests/compiler/dart2js/serialization_resolved_ast_test.dart
@@ -20,11 +20,13 @@
import 'serialization_test_helper.dart';
-main(List<String> arguments) {
+main(List<String> args) {
+ Arguments arguments = new Arguments.from(args);
asyncTest(() async {
- String serializedData = await serializeDartCore(serializeResolvedAst: true);
- if (arguments.isNotEmpty) {
- Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.last));
+ String serializedData = await serializeDartCore(
+ arguments: arguments, serializeResolvedAst: true);
+ if (arguments.filename != null) {
+ Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
await check(serializedData, entryPoint);
} else {
Uri entryPoint = Uri.parse('memory:main.dart');
@@ -43,13 +45,13 @@
Compiler compilerNormal = compilerFor(
memorySourceFiles: sourceFiles,
- options: [Flags.analyzeOnly]);
+ options: [Flags.analyzeAll]);
compilerNormal.resolution.retainCachesForTesting = true;
await compilerNormal.run(entryPoint);
Compiler compilerDeserialized = compilerFor(
memorySourceFiles: sourceFiles,
- options: [Flags.analyzeOnly]);
+ options: [Flags.analyzeAll]);
compilerDeserialized.resolution.retainCachesForTesting = true;
deserialize(
compilerDeserialized, serializedData, deserializeResolvedAst: true);
@@ -69,7 +71,7 @@
return compiler1.resolution.hasResolvedAst(member1);
},
checkResolvedAsts,
- verbose: true);
+ verbose: verbose);
}
diff --git a/tests/compiler/dart2js/serialization_test.dart b/tests/compiler/dart2js/serialization_test.dart
index fd6ae58..9d15022 100644
--- a/tests/compiler/dart2js/serialization_test.dart
+++ b/tests/compiler/dart2js/serialization_test.dart
@@ -8,6 +8,7 @@
import 'memory_compiler.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/common.dart';
import 'package:compiler/src/constants/constructors.dart';
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/dart_types.dart';
@@ -347,7 +348,6 @@
throw message;
}
}
- //print('Checking member ${member1} against ${member2}');
visit(member1, member2);
}
}
@@ -480,6 +480,10 @@
checkElementProperties);
check(element1, element2, 'isOperator',
element1.isOperator, element2.isOperator);
+ check(
+ element1, element2, 'asyncMarker',
+ element1.asyncMarker,
+ element2.asyncMarker);
checkElementIdentities(
element1, element2, 'library',
@@ -490,6 +494,44 @@
checkElementIdentities(
element1, element2, 'enclosingClass',
element1.enclosingClass, element2.enclosingClass);
+
+ check(
+ element1, element2, 'functionSignature.type',
+ element1.functionSignature.type,
+ element2.functionSignature.type,
+ areTypesEquivalent);
+ checkElementLists(
+ element1, element2, 'functionSignature.requiredParameters',
+ element1.functionSignature.requiredParameters,
+ element2.functionSignature.requiredParameters);
+ checkElementLists(
+ element1, element2, 'functionSignature.optionalParameters',
+ element1.functionSignature.optionalParameters,
+ element2.functionSignature.optionalParameters);
+ check(
+ element1, element2, 'functionSignature.requiredParameterCount',
+ element1.functionSignature.requiredParameterCount,
+ element2.functionSignature.requiredParameterCount);
+ check(
+ element1, element2, 'functionSignature.optionalParameterCount',
+ element1.functionSignature.optionalParameterCount,
+ element2.functionSignature.optionalParameterCount);
+ check(
+ element1, element2, 'functionSignature.optionalParametersAreNamed',
+ element1.functionSignature.optionalParametersAreNamed,
+ element2.functionSignature.optionalParametersAreNamed);
+ check(
+ element1, element2, 'functionSignature.hasOptionalParameters',
+ element1.functionSignature.hasOptionalParameters,
+ element2.functionSignature.hasOptionalParameters);
+ check(
+ element1, element2, 'functionSignature.parameterCount',
+ element1.functionSignature.parameterCount,
+ element2.functionSignature.parameterCount);
+ checkElementLists(
+ element1, element2, 'functionSignature.orderedOptionalParameters',
+ element1.functionSignature.orderedOptionalParameters,
+ element2.functionSignature.orderedOptionalParameters);
}
@override
@@ -586,6 +628,9 @@
check(
element1, element2, 'isNamed',
element1.isNamed, element2.isNamed);
+ check(
+ element1, element2, 'isFinal',
+ element1.isFinal, element2.isFinal);
check(element1, element2, 'name', element1.name, element2.name);
if (element1.isOptional) {
checkConstants(
diff --git a/tests/compiler/dart2js/serialization_test_data.dart b/tests/compiler/dart2js/serialization_test_data.dart
index 67d400c..3056735 100644
--- a/tests/compiler/dart2js/serialization_test_data.dart
+++ b/tests/compiler/dart2js/serialization_test_data.dart
@@ -188,6 +188,19 @@
},
expectedWarningCount: 1,
expectedInfoCount: 0),
+
+ const Test(const {
+ 'main.dart': '''
+main() {
+ loop: for (var a in []) {
+ for (var b in []) {
+ continue loop;
+ }
+ break;
+ }
+}'''
+ }),
+
];
class Test {
diff --git a/tests/compiler/dart2js/serialization_test_helper.dart b/tests/compiler/dart2js/serialization_test_helper.dart
index 97d5134..4ee842d 100644
--- a/tests/compiler/dart2js/serialization_test_helper.dart
+++ b/tests/compiler/dart2js/serialization_test_helper.dart
@@ -104,9 +104,9 @@
bool check(var object1, var object2, String property, var value1, var value2,
[bool equivalence(a, b) = equality]) {
if (!equivalence(value1, value2)) {
- throw "property='$property' "
- "object1=$object1 (${object1.runtimeType}), value='${value1}' <> "
- "object2=$object2 (${object2.runtimeType}), value='${value2}'";
+ throw "property='$property'\n "
+ "object1=$object1 (${object1.runtimeType})\n value='${value1}' <>\n "
+ "object2=$object2 (${object2.runtimeType})\n value='${value2}'";
}
return true;
}
@@ -212,12 +212,8 @@
Object object1, Object object2, String property,
Element element1, Element element2) {
if (identical(element1, element2)) return true;
- if (element1 == null || element2 == null) {
- return check(object1, object2, property, element1, element2);
- } else {
- return const ElementIdentityEquivalence(const CheckStrategy())
- .visit(element1, element2);
- }
+ return check(object1, object2,
+ property, element1, element2, areElementsEquivalent);
}
/// Checks the pair-wise equivalence of the identity (but not properties) of the
@@ -298,9 +294,20 @@
if (member1.isClass && member2.isClass) {
ClassElement class1 = member1;
ClassElement class2 = member2;
+ if (!class1.isResolved) return;
+
class1.forEachLocalMember((m1) {
- checkMembers(m1, class2.lookupLocalMember(m1.name));
+ checkMembers(m1, class2.localLookup(m1.name));
});
+ ClassElement superclass1 = class1.superclass;
+ ClassElement superclass2 = class2.superclass;
+ while (superclass1 != null && superclass1.isUnnamedMixinApplication) {
+ for (ConstructorElement c1 in superclass1.constructors) {
+ checkMembers(c1, superclass2.lookupConstructor(c1.name));
+ }
+ superclass1 = superclass1.superclass;
+ superclass2 = superclass2.superclass;
+ }
return;
}
@@ -309,7 +316,7 @@
}
if (member2 == null) {
- return;
+ throw 'Missing member for ${member1}';
}
if (areElementsEquivalent(member1, member2)) {
@@ -344,7 +351,7 @@
return compiler1.resolution.hasResolutionImpact(member1);
},
checkImpacts,
- verbose: true);
+ verbose: verbose);
}
/// Check equivalence of resolution impact for [member1] and [member2].
@@ -352,14 +359,20 @@
Compiler compiler2, Element member2,
{bool verbose: false}) {
ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1);
- ResolutionImpact impact2 =
- compiler2.serialization.deserializer.getResolutionImpact(member2);
+ ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2);
- if (impact1 == null || impact2 == null) return;
+ if (impact1 == null && impact2 == null) return;
if (verbose) {
print('Checking impacts for $member1 vs $member2');
}
+ if (impact1 == null) {
+ throw 'Missing impact for $member1. $member2 has $impact2';
+ }
+ if (impact2 == null) {
+ throw 'Missing impact for $member2. $member1 has $impact1';
+ }
+
testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy());
}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 446062f..0b3fb87 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -2513,13 +2513,13 @@
classElement.forEachLocalMember((Element e) {
if (!e.isSynthesized) {
element = e;
- node = element.parseNode(compiler.parsing);
+ node = element.parseNode(compiler.parsingContext);
compiler.resolver.resolve(element);
mapping = element.treeElements;
}
});
} else {
- node = element.parseNode(compiler.parsing);
+ node = element.parseNode(compiler.parsingContext);
compiler.resolver.resolve(element);
mapping = element.treeElements;
}
diff --git a/tests/compiler/dart2js/user_crash_test.dart b/tests/compiler/dart2js/user_crash_test.dart
new file mode 100644
index 0000000..305de2a
--- /dev/null
+++ b/tests/compiler/dart2js/user_crash_test.dart
@@ -0,0 +1,102 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/compiler_new.dart';
+import 'memory_compiler.dart';
+
+final EXCEPTION = 'Crash';
+
+main() {
+ asyncTest(() async {
+ test('Empty program', await run());
+ test('Crash diagnostics',
+ await run(diagnostics: new CrashingDiagnostics()),
+ expectedLines: [
+ 'Uncaught exception in diagnostic handler: $EXCEPTION',
+ null /* Stack trace*/],
+ expectedExceptions: [EXCEPTION]);
+ test('Throw in package discovery',
+ await run(packagesDiscoveryProvider: (_) { throw EXCEPTION; }),
+ expectedLines: [
+ 'Uncaught exception in package discovery: $EXCEPTION',
+ null /* Stack trace*/],
+ expectedExceptions: [EXCEPTION]);
+ test('new Future.error in package discovery',
+ await run(packagesDiscoveryProvider:
+ (_) => new Future.error(EXCEPTION)),
+ expectedExceptions: [EXCEPTION]);
+ test('Throw in input provider',
+ await run(memorySourceFiles: new CrashingMap()),
+ expectedLines: [
+ 'Uncaught exception in input provider: $EXCEPTION',
+ null, // Stack trace
+ 'memory:main.dart:\nError: $EXCEPTION' /* READ_SELF_ERROR */]);
+ });
+}
+
+void test(String title, RunResult result,
+ {List expectedLines: const [],
+ List expectedExceptions: const []}) {
+ print('--------------------------------------------------------------------');
+ print('Running $title');
+ print('--------------------------------------------------------------------');
+ print('lines:');
+ result.lines.forEach(print);
+ print('exceptions:');
+ result.exceptions.forEach(print);
+ Expect.equals(expectedLines.length, result.lines.length,
+ "Unexpected number of calls to print.");
+ Expect.equals(expectedExceptions.length, result.exceptions.length,
+ "Unexpected number of exceptions.");
+ for (int i = 0; i < expectedLines.length; i++) {
+ if (expectedLines[i] != null) {
+ Expect.equals(expectedLines[i], result.lines[i]);
+ }
+ }
+}
+
+Future<RunResult> run(
+ {Map<String, String> memorySourceFiles: const {'main.dart': 'main() {}'},
+ CompilerDiagnostics diagnostics,
+ PackagesDiscoveryProvider packagesDiscoveryProvider}) async {
+ RunResult result = new RunResult();
+ await runZoned(() async {
+ try {
+ await runCompiler(
+ entryPoint: Uri.parse('memory:main.dart'),
+ memorySourceFiles: memorySourceFiles,
+ diagnosticHandler: diagnostics,
+ packagesDiscoveryProvider: packagesDiscoveryProvider);
+ } catch (e) {
+ result.exceptions.add(e);
+ }
+
+ },
+ zoneSpecification: new ZoneSpecification(print:
+ (Zone self, ZoneDelegate parent, Zone zone, String line) {
+ result.lines.add(line);
+ }));
+ return result;
+}
+
+class RunResult {
+ List<String> lines = <String>[];
+ List exceptions = [];
+}
+
+class CrashingDiagnostics extends DiagnosticCollector {
+ @override
+ void report(code, Uri uri, int begin, int end, String text, Diagnostic kind) {
+ throw EXCEPTION;
+ }
+}
+
+class CrashingMap implements Map<String, String> {
+ operator [](_) => throw EXCEPTION;
+
+ noSuchMethod(_) => null;
+}
\ No newline at end of file
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index fe92613..60a6bc5 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -207,4 +207,7 @@
data_resource_test: Skip # Resolve URI not supported yet in product mode.
package_resource_test: Skip # Resolve URI not supported yet in product mode.
file_resource_test: Skip # Resolve URI not supported yet in product mode.
-http_resource_test: Skip # Resolve URI not supported yet in product mode.
\ No newline at end of file
+http_resource_test: Skip # Resolve URI not supported yet in product mode.
+
+[ $arch == simdbc || $arch == simdbc64 ]
+regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
diff --git a/tests/corelib/uri_test.dart b/tests/corelib/uri_test.dart
index fd281c5..f1dce7a 100644
--- a/tests/corelib/uri_test.dart
+++ b/tests/corelib/uri_test.dart
@@ -407,7 +407,8 @@
var fragment = uri1.hasFragment ? uri1.fragment : null;
var tmp1 = uri1;
- test() {
+
+ void test() {
var tmp2 = new Uri(scheme: scheme, userInfo: userInfo, host: host,
port: port, path: path,
query: query == "" ? null : query,
@@ -452,6 +453,14 @@
var uri = Uri.parse("/no-authorty/");
uri = uri.replace(fragment: "fragment");
Expect.isFalse(uri.hasAuthority);
+
+ uri = new Uri(scheme: "foo", path: "bar");
+ uri = uri.replace(
+ queryParameters: {"x": ["42", "37"], "y": ["43", "38"]});
+ var params = uri.queryParametersAll;
+ Expect.equals(2, params.length);
+ Expect.listEquals(["42", "37"], params["x"]);
+ Expect.listEquals(["43", "38"], params["y"]);
}
main() {
diff --git a/tests/html/element_test.dart b/tests/html/element_test.dart
index 42c4ebe..c1f74b5 100644
--- a/tests/html/element_test.dart
+++ b/tests/html/element_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
library ElementTest;
+
import 'package:unittest/unittest.dart';
import 'package:unittest/html_individual_config.dart';
import 'dart:async';
@@ -47,7 +48,7 @@
Element makeElement() => new Element.tag('div');
Element makeElementWithChildren() =>
- new Element.html("<div><br/><img/><input/></div>");
+ new Element.html("<div><br/><img/><input/></div>");
group('position', () {
test('computedStyle', () {
@@ -87,8 +88,8 @@
expect(() => new Element.html('<br/><br/>'), throwsStateError);
});
- test('.html has no parent', () =>
- expect(new Element.html('<br/>').parent, isNull));
+ test('.html has no parent',
+ () => expect(new Element.html('<br/>').parent, isNull));
test('.html table', () {
// http://developers.whatwg.org/tabular-data.html#tabular-data
@@ -126,8 +127,10 @@
test('.html caption', () {
var table = new TableElement();
var node = table.createFragment('<caption><p>Table 1.').nodes.single;
- expect(node, predicate((x) => x is TableCaptionElement,
- 'is a TableCaptionElement'));
+ expect(
+ node,
+ predicate(
+ (x) => x is TableCaptionElement, 'is a TableCaptionElement'));
expect(node.tagName, 'CAPTION');
expect(node.parent, isNull);
expect(node.innerHtml, '<p>Table 1.</p>');
@@ -137,8 +140,8 @@
var table = new TableElement();
var node =
table.createFragment('<colgroup> <col> <col> <col>').nodes.single;
- expect(node, predicate((x) => x is TableColElement,
- 'is a TableColElement'));
+ expect(
+ node, predicate((x) => x is TableColElement, 'is a TableColElement'));
expect(node.tagName, 'COLGROUP');
expect(node.parent, isNull);
expect(node.innerHtml, ' <col> <col> <col>');
@@ -148,8 +151,10 @@
var innerHtml = '<tr><td headers="n r1">Sad</td><td>Happy</td></tr>';
var table = new TableElement();
var node = table.createFragment('<tbody>$innerHtml').nodes.single;
- expect(node, predicate((x) => x is TableSectionElement,
- 'is a TableSectionElement'));
+ expect(
+ node,
+ predicate(
+ (x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'TBODY');
expect(node.parent, isNull);
expect(node.rows.length, 1);
@@ -161,8 +166,10 @@
var innerHtml = '<tr><th id="n">Negative</th><th>Positive</th></tr>';
var table = new TableElement();
var node = table.createFragment('<thead>$innerHtml').nodes.single;
- expect(node, predicate((x) => x is TableSectionElement,
- 'is a TableSectionElement'));
+ expect(
+ node,
+ predicate(
+ (x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'THEAD');
expect(node.parent, isNull);
expect(node.rows.length, 1);
@@ -174,8 +181,10 @@
var innerHtml = '<tr><th>percentage</th><td>34.3%</td></tr>';
var table = new TableElement();
var node = table.createFragment('<tfoot>$innerHtml').nodes.single;
- expect(node, predicate((x) => x is TableSectionElement,
- 'is a TableSectionElement'));
+ expect(
+ node,
+ predicate(
+ (x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'TFOOT');
expect(node.parent, isNull);
expect(node.rows.length, 1);
@@ -188,8 +197,8 @@
document.body.append(table);
var tBody = table.createTBody();
var node = tBody.createFragment('<tr><td>foo<td>bar').nodes.single;
- expect(node, predicate((x) => x is TableRowElement,
- 'is a TableRowElement'));
+ expect(
+ node, predicate((x) => x is TableRowElement, 'is a TableRowElement'));
expect(node.tagName, 'TR');
expect(node.parent, isNull);
expect(node.cells.map((c) => c.innerHtml), ['foo', 'bar']);
@@ -201,8 +210,8 @@
var tBody = table.createTBody();
var tRow = tBody.addRow();
var node = tRow.createFragment('<td>foobar').nodes.single;
- expect(node, predicate((x) => x is TableCellElement,
- 'is a TableCellElement'));
+ expect(node,
+ predicate((x) => x is TableCellElement, 'is a TableCellElement'));
expect(node.tagName, 'TD');
expect(node.parent, isNull);
expect(node.innerHtml, 'foobar');
@@ -214,8 +223,8 @@
var tBody = table.createTBody();
var tRow = tBody.addRow();
var node = tRow.createFragment('<th>foobar').nodes.single;
- expect(node, predicate((x) => x is TableCellElement,
- 'is a TableCellElement'));
+ expect(node,
+ predicate((x) => x is TableCellElement, 'is a TableCellElement'));
expect(node.tagName, 'TH');
expect(node.parent, isNull);
expect(node.innerHtml, 'foobar');
@@ -234,15 +243,15 @@
group('eventListening', () {
test('streams', () {
- final target = new Element.tag('div');
+ final target = new TextAreaElement();
- void testEvent(Stream stream, String type) {
+ void testEvent(Stream stream, String type, [createEvent(String type)]) {
var firedOnEvent = false;
stream.listen((e) {
firedOnEvent = true;
});
expect(firedOnEvent, isFalse);
- var event = new Event(type);
+ var event = createEvent != null ? createEvent(type) : new Event(type);
target.dispatchEvent(event);
expect(firedOnEvent, isTrue);
@@ -254,38 +263,53 @@
testEvent(target.onBeforePaste, 'beforepaste');
testEvent(target.onBlur, 'blur');
testEvent(target.onChange, 'change');
- testEvent(target.onContextMenu, 'contextmenu');
+ testEvent(
+ target.onContextMenu, 'contextmenu', (type) => new MouseEvent(type));
+ // We cannot test dispatching a true ClipboardEvent as the DOM does not
+ // provide a way to create a fake ClipboardEvent.
testEvent(target.onCopy, 'copy');
testEvent(target.onCut, 'cut');
- testEvent(target.onDoubleClick, 'dblclick');
- testEvent(target.onDrag, 'drag');
- testEvent(target.onDragEnd, 'dragend');
- testEvent(target.onDragEnter, 'dragenter');
- testEvent(target.onDragLeave, 'dragleave');
- testEvent(target.onDragOver, 'dragover');
- testEvent(target.onDragStart, 'dragstart');
- testEvent(target.onDrop, 'drop');
+ testEvent(target.onPaste, 'paste');
+
+ testEvent(
+ target.onDoubleClick, 'dblclick', (type) => new MouseEvent(type));
+ testEvent(target.onDrag, 'drag', (type) => new MouseEvent(type));
+ testEvent(target.onDragEnd, 'dragend', (type) => new MouseEvent(type));
+ testEvent(
+ target.onDragEnter, 'dragenter', (type) => new MouseEvent(type));
+ testEvent(
+ target.onDragLeave, 'dragleave', (type) => new MouseEvent(type));
+ testEvent(target.onDragOver, 'dragover', (type) => new MouseEvent(type));
+ testEvent(
+ target.onDragStart, 'dragstart', (type) => new MouseEvent(type));
+ testEvent(target.onDrop, 'drop', (type) => new MouseEvent(type));
testEvent(target.onError, 'error');
testEvent(target.onFocus, 'focus');
testEvent(target.onFullscreenChange, 'webkitfullscreenchange');
testEvent(target.onInput, 'input');
testEvent(target.onInvalid, 'invalid');
- testEvent(target.onKeyDown, 'keydown');
- testEvent(target.onKeyPress, 'keypress');
- testEvent(target.onKeyUp, 'keyup');
+ testEvent(target.onKeyDown, 'keydown', (type) => new KeyboardEvent(type));
+ testEvent(
+ target.onKeyPress, 'keypress', (type) => new KeyboardEvent(type));
+ testEvent(target.onKeyUp, 'keyup', (type) => new KeyboardEvent(type));
testEvent(target.onLoad, 'load');
- testEvent(target.onMouseDown, 'mousedown');
- testEvent(target.onMouseMove, 'mousemove');
- testEvent(target.onMouseOut, 'mouseout');
- testEvent(target.onMouseOver, 'mouseover');
- testEvent(target.onMouseUp, 'mouseup');
- testEvent(target.onPaste, 'paste');
+ testEvent(
+ target.onMouseDown, 'mousedown', (type) => new MouseEvent(type));
+ testEvent(
+ target.onMouseMove, 'mousemove', (type) => new MouseEvent(type));
+ testEvent(target.onMouseOut, 'mouseout', (type) => new MouseEvent(type));
+ testEvent(
+ target.onMouseOver, 'mouseover', (type) => new MouseEvent(type));
+ testEvent(target.onMouseUp, 'mouseup', (type) => new MouseEvent(type));
testEvent(target.onReset, 'reset');
testEvent(target.onScroll, 'scroll');
testEvent(target.onSearch, 'search');
testEvent(target.onSelect, 'select');
testEvent(target.onSelectStart, 'selectstart');
testEvent(target.onSubmit, 'submit');
+ // We would prefer to create new touch events for this test via
+ // new TouchEvent(null, null, null, type)
+ // but that fails on desktop browsers as touch is not enabled.
testEvent(target.onTouchCancel, 'touchcancel');
testEvent(target.onTouchEnd, 'touchend');
testEvent(target.onTouchLeave, 'touchleave');
@@ -319,66 +343,67 @@
});
group('attributes', () {
- test('manipulation', () {
- final element = new Element.html(
- '''<div class="foo" style="overflow: hidden" data-foo="bar"
+ test('manipulation', () {
+ final element = new Element.html(
+ '''<div class="foo" style="overflow: hidden" data-foo="bar"
data-foo2="bar2" dir="rtl">
- </div>''', treeSanitizer: new NullTreeSanitizer());
- final attributes = element.attributes;
- expect(attributes['class'], 'foo');
- expect(attributes['style'], startsWith('overflow: hidden'));
- expect(attributes['data-foo'], 'bar');
- expect(attributes['data-foo2'], 'bar2');
- expect(attributes.length, 5);
- expect(element.dataset.length, 2);
- element.dataset['foo'] = 'baz';
- expect(element.dataset['foo'], 'baz');
- expect(attributes['data-foo'], 'baz');
- attributes['data-foo2'] = 'baz2';
- expect(attributes['data-foo2'], 'baz2');
- expect(element.dataset['foo2'], 'baz2');
- expect(attributes['dir'], 'rtl');
+ </div>''',
+ treeSanitizer: new NullTreeSanitizer());
+ final attributes = element.attributes;
+ expect(attributes['class'], 'foo');
+ expect(attributes['style'], startsWith('overflow: hidden'));
+ expect(attributes['data-foo'], 'bar');
+ expect(attributes['data-foo2'], 'bar2');
+ expect(attributes.length, 5);
+ expect(element.dataset.length, 2);
+ element.dataset['foo'] = 'baz';
+ expect(element.dataset['foo'], 'baz');
+ expect(attributes['data-foo'], 'baz');
+ attributes['data-foo2'] = 'baz2';
+ expect(attributes['data-foo2'], 'baz2');
+ expect(element.dataset['foo2'], 'baz2');
+ expect(attributes['dir'], 'rtl');
- final dataset = element.dataset;
- dataset.remove('foo2');
- expect(attributes.length, 4);
- expect(dataset.length, 1);
- attributes.remove('style');
- expect(attributes.length, 3);
- dataset['foo3'] = 'baz3';
- expect(dataset.length, 2);
- expect(attributes.length, 4);
- attributes['style'] = 'width: 300px;';
- expect(attributes.length, 5);
- });
+ final dataset = element.dataset;
+ dataset.remove('foo2');
+ expect(attributes.length, 4);
+ expect(dataset.length, 1);
+ attributes.remove('style');
+ expect(attributes.length, 3);
+ dataset['foo3'] = 'baz3';
+ expect(dataset.length, 2);
+ expect(attributes.length, 4);
+ attributes['style'] = 'width: 300px;';
+ expect(attributes.length, 5);
+ });
- test('namespaces', () {
- var element = new svg.SvgElement.svg(
- '''<svg xmlns="http://www.w3.org/2000/svg"
+ test('namespaces', () {
+ var element =
+ new svg.SvgElement.svg('''<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="foo" data-foo="bar"/>
</svg>''').children[0];
- var attributes = element.attributes;
- expect(attributes.length, 1);
- expect(attributes['data-foo'], 'bar');
+ var attributes = element.attributes;
+ expect(attributes.length, 1);
+ expect(attributes['data-foo'], 'bar');
- var xlinkAttrs =
- element.getNamespacedAttributes('http://www.w3.org/1999/xlink');
- expect(xlinkAttrs.length, 1);
- expect(xlinkAttrs['href'], 'foo');
+ var xlinkAttrs =
+ element.getNamespacedAttributes('http://www.w3.org/1999/xlink');
+ expect(xlinkAttrs.length, 1);
+ expect(xlinkAttrs['href'], 'foo');
- xlinkAttrs.remove('href');
- expect(xlinkAttrs.length, 0);
+ xlinkAttrs.remove('href');
+ expect(xlinkAttrs.length, 0);
- xlinkAttrs['href'] = 'bar';
- expect(xlinkAttrs['href'], 'bar');
+ xlinkAttrs['href'] = 'bar';
+ expect(xlinkAttrs['href'], 'bar');
- var randomAttrs = element.getNamespacedAttributes('http://example.com');
- expect(randomAttrs.length, 0);
- randomAttrs['href'] = 'bar';
- expect(randomAttrs.length, 1);
- });
+ var randomAttrs = element.getNamespacedAttributes('http://example.com');
+ expect(randomAttrs.length, 0);
+ randomAttrs['href'] = 'bar';
+ expect(randomAttrs.length, 1);
+ });
});
group('children', () {
@@ -421,8 +446,8 @@
});
test('where', () {
- var filtered = makeElementWithChildren().children.
- where((n) => n is ImageElement);
+ var filtered =
+ makeElementWithChildren().children.where((n) => n is ImageElement);
expect(1, filtered.length);
expect(filtered.first, isImageElement);
expect(filtered, isElementIterable);
@@ -764,25 +789,27 @@
test('matches', () {
Element clickOne = new Element.a();
Element selectorOne = new Element.div()
- ..classes.add('selector')
- ..children.add(clickOne);
+ ..classes.add('selector')
+ ..children.add(clickOne);
Element clickTwo = new Element.a();
Element selectorTwo = new Element.div()
- ..classes.add('selector')
- ..children.add(clickTwo);
+ ..classes.add('selector')
+ ..children.add(clickTwo);
document.body.append(selectorOne);
document.body.append(selectorTwo);
- document.body.onClick.matches('.selector').listen(expectAsync(
- (Event event) {
+ document.body.onClick
+ .matches('.selector')
+ .listen(expectAsync((Event event) {
expect(event.currentTarget, document.body);
expect(event.target, clickOne);
expect(event.matchingTarget, selectorOne);
}));
- selectorOne.onClick.matches('.selector').listen(expectAsync(
- (Event event) {
+ selectorOne.onClick
+ .matches('.selector')
+ .listen(expectAsync((Event event) {
expect(event.currentTarget, selectorOne);
expect(event.target, clickOne);
expect(event.matchingTarget, selectorOne);
@@ -896,12 +923,8 @@
var event = new Event('custom_event', canBubble: true);
c.dispatchEvent(event);
- expect(eventOrder, [
- 'a capture',
- 'b capture',
- 'b no-capture',
- 'a no-capture'
- ]);
+ expect(eventOrder,
+ ['a capture', 'b capture', 'b no-capture', 'a no-capture']);
});
});
@@ -917,7 +940,7 @@
ElementList<Element> makeElementList() =>
(new Element.html("<div>Foo<br/><!--baz--><br/><br/></div>"))
- .queryAll('br');
+ .queryAll('br');
test('hashCode', () {
var nodes = makeElementList();
@@ -934,7 +957,7 @@
var a = [makeElementList(), makeElementList(), null];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
- expect(i == j, a[i] == a[j]);
+ expect(i == j, a[i] == a[j]);
}
}
});
@@ -973,6 +996,5 @@
expect(range[0], isBRElement);
expect(range[1], isBRElement);
});
-
});
}
diff --git a/tests/html/events_test.dart b/tests/html/events_test.dart
index b2c448a..9d09bf6 100644
--- a/tests/html/events_test.dart
+++ b/tests/html/events_test.dart
@@ -51,7 +51,7 @@
element.dispatchEvent(event);
expect(invocationCounter, isZero);
- var provider = new EventStreamProvider<CustomEvent>('test');
+ var provider = new EventStreamProvider<Event>('test');
var sub = provider.forTarget(element).listen(handler);
invocationCounter = 0;
diff --git a/tests/html/html.status b/tests/html/html.status
index 4beb9f4..2b538fc 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -60,9 +60,7 @@
fileapi_test/getFile: Pass, Fail # Issue 20488
async_test: RuntimeError, OK # Uses Isolate.spawn.
isolates_test: RuntimeError, OK # Uses Isolate.spawn.
-
-[ $compiler == none && ($runtime == drt || $runtime == dartium ) && $checked]
-cross_domain_iframe_test: RuntimeError # Issue 26134
+custom/created_callback_test: Fail # Support for created constructor. Issue 14835
[ $compiler == none && ($runtime == drt || $runtime == dartium ) && $mode == debug ]
websocket_test/websocket: Skip # Issue 17666
diff --git a/tests/language/generic_functions_test.dart b/tests/language/generic_functions_test.dart
index 54ab173..814163a 100644
--- a/tests/language/generic_functions_test.dart
+++ b/tests/language/generic_functions_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import "package:expect/expect.dart";
+/// Dart test verifying that the parser can handle type parameterization of
+/// function declarations and function invocations. Variant of code from
+/// DEP #22, adjusted to use generic top level functions.
-// Dart test verifying that the parser can handle type parameterization of
-// function declarations and function invocations. Variant of code from
-// DEP #22, adjusted to use generic top level functions.
+library generic_functions_test;
+
+import "package:expect/expect.dart";
class BinaryTreeNode<K extends Comparable<K>, V> {
final K _key;
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
new file mode 100644
index 0000000..6a350d4
--- /dev/null
+++ b/tests/language/generic_local_functions_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Dart test verifying that the parser can handle type parameterization of
+/// local function declarations, and declarations of function parameters.
+
+library generic_functions_test;
+
+import "package:expect/expect.dart";
+
+// Declare a generic function parameter.
+String f(int g<X, Y>(Map<X, Y> arg)) => null;
+
+main() {
+ // Declare a generic local function
+ int h<X extends Y, Y>(Map<X, Y> arg) => null;
+ // Pass a generic local function as an argument.
+ f(h);
+ // Pass a function expression as an argument.
+ f(<X, Y super X>(Map<X, Y> arg) => 42);
+}
diff --git a/tests/language/generic_local_functions_test.options b/tests/language/generic_local_functions_test.options
new file mode 100644
index 0000000..86e2aac
--- /dev/null
+++ b/tests/language/generic_local_functions_test.options
@@ -0,0 +1,3 @@
+analyzer:
+ language:
+ enableGenericMethods: true
diff --git a/tests/language/generic_methods_test.dart b/tests/language/generic_methods_test.dart
index 3fd6d24..9151fc3 100644
--- a/tests/language/generic_methods_test.dart
+++ b/tests/language/generic_methods_test.dart
@@ -2,11 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import "package:expect/expect.dart";
+/// Dart test verifying that the parser can handle type parameterization of
+/// method declarations and method invocations. Slightly adjusted version of
+/// code from DEP #22.
-// Dart test verifying that the parser can handle type parameterization of
-// method declarations and method invocations. Slightly adjusted version of
-// code from DEP #22.
+library generic_methods_test;
+
+import "package:expect/expect.dart";
class BinaryTreeNode<K extends Comparable<K>, V> {
final K _key;
diff --git a/tests/language/generic_sends_test.dart b/tests/language/generic_sends_test.dart
index 2e98215d..57befee 100644
--- a/tests/language/generic_sends_test.dart
+++ b/tests/language/generic_sends_test.dart
@@ -2,9 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// Dart test verifying that the parser can handle certain cases where
-// grammar ambiguity is resolved in favor of generic sends, not
-// relational expressions.
+/// Dart test verifying that the parser can handle certain cases where
+/// grammar ambiguity is resolved in favor of generic sends, not
+/// relational expressions.
+
+library generic_sends_test;
f(arg1, [arg2]) => null;
g<X, Y>(arg) => null;
diff --git a/tests/language/language.status b/tests/language/language.status
index 044e7a5..c3a14b9 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -47,6 +47,7 @@
# Experimental feature: Syntactic support for generic methods.
generic_methods_test: CompiletimeError # Issue 25869
generic_functions_test: CompiletimeError # Issue 25869
+generic_local_functions_test: CompiletimeError # Issue 25869
generic_sends_test: CompiletimeError # Issue 25869
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
@@ -91,7 +92,9 @@
# Experimental feature: Syntactic support for generic methods.
generic_methods_test: RuntimeError # Issue 25869
generic_functions_test: RuntimeError # Issue 25869
+generic_local_functions_test: RuntimeError # Issue 25869
generic_sends_test: RuntimeError # Issue 25869
+config_import_test: Skip # Issue 26250
[ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
issue_22780_test/01: Pass, Timeout # Issue 24473
@@ -208,3 +211,11 @@
[ $noopt || $compiler == precompiler || $mode == product ]
# The following tests are supposed to fail.
library_env_test/has_mirror_support: RuntimeError, OK
+
+[ $arch == simdbc || $arch == simdbc64 ]
+# TODO(vegorov) StopInstr is unimplemented.
+vm/debug_break_enabled_vm_test/none: Skip
+
+# TODO(vegorov) Encoding limitation: StoreField bytecode only supports 256
+# fields in an object.
+large_class_declaration_test: Skip
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index c8c95f3..a588be3 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -520,5 +520,6 @@
# Experimental feature: Syntactic support for generic methods.
generic_functions_test: CompileTimeError # Issue 25868
+generic_local_functions_test: CompileTimeError # Issue 25868
generic_methods_test: CompileTimeError # Issue 25868
generic_sends_test: CompileTimeError # Issue 25868
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index f10bd63..4a95853 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -37,6 +37,7 @@
# Experimental feature: Syntactic support for generic methods.
generic_functions_test: CompileTimeError # Issue 25835
+generic_local_functions_test: CompileTimeError # Issue 25835
generic_methods_test: CompileTimeError # Issue 25835
generic_sends_test: CompileTimeError # Issue 25835
diff --git a/tests/language/regress_26230_test.dart b/tests/language/regress_26230_test.dart
new file mode 100644
index 0000000..c6de7d7
--- /dev/null
+++ b/tests/language/regress_26230_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _RenderTabBar extends RenderBox with
+ ContainerRenderObjectMixin<RenderBox, _TabBarParentData>,
+ RenderBoxContainerDefaultsMixin<RenderBox, _TabBarParentData> { }
+class RenderObject { }
+class RenderSector extends RenderObject { }
+class RenderBox extends RenderObject { }
+class ParentData { }
+class BoxParentData extends ParentData { }
+class SectorParentData extends ParentData { }
+class ContainerParentDataMixin<ChildType extends RenderObject> { }
+class ContainerRenderObjectMixin<ChildType extends RenderObject, ParentDataType extends ContainerParentDataMixin<ChildType>> { }
+class SectorChildListParentData extends SectorParentData with ContainerParentDataMixin<RenderSector> { }
+class RenderDecoratedSector extends RenderSector { }
+class RenderSectorWithChildren extends RenderDecoratedSector with ContainerRenderObjectMixin<RenderSector, SectorChildListParentData> { }
+class ContainerBoxParentDataMixin<ChildType extends RenderObject> extends BoxParentData with ContainerParentDataMixin<ChildType> { }
+class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, ParentDataType extends ContainerBoxParentDataMixin<ChildType>> implements ContainerRenderObjectMixin<ChildType, ParentDataType> { }
+class FlexParentData extends ContainerBoxParentDataMixin<RenderBox> { }
+class _TabBarParentData extends ContainerBoxParentDataMixin<RenderBox> { }
+
+main() {
+ new _RenderTabBar();
+}
+
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 3288d18..b86abdc 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -17,12 +17,12 @@
lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError # Issue 16522
[ $compiler == dart2analyzer ]
-lib/web_gl/dartium/web_gl_dartium: CompileTimeError # Issue 21647
-lib/web_sql/dartium/web_sql_dartium: CompileTimeError # Issue 21647
-lib/html/dartium/html_dartium: CompileTimeError # Issue 21647
-lib/html/html_common/html_common: CompileTimeError # Issue 21647
-lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError # Issue 21647
-lib/web_audio/dartium/web_audio_dartium: CompileTimeError # Issue 21647
-lib/svg/dartium/svg_dartium: CompileTimeError # Issue 21647
-lib/_blink/dartium/_blink_dartium: CompileTimeError # Undefined Creates and Returns classes
-lib/js/dartium/js_dartium: CompileTimeError # Undefined Creates and Returns classes
\ No newline at end of file
+lib/web_gl/dartium/web_gl_dartium: StaticWarning # Issue 21647
+lib/web_sql/dartium/web_sql_dartium: StaticWarning # Issue 21647
+lib/html/dartium/html_dartium: StaticWarning # Issue 21647
+lib/html/html_common/html_common: StaticWarning # Issue 21647
+lib/indexed_db/dartium/indexed_db_dartium: StaticWarning # Issue 21647
+lib/web_audio/dartium/web_audio_dartium: StaticWarning # Issue 21647
+lib/svg/dartium/svg_dartium: StaticWarning # Issue 21647
+lib/_blink/dartium/_blink_dartium: StaticWarning # Undefined Creates and Returns classes
+lib/js/dartium/js_dartium: StaticWarning # Undefined Creates and Returns classes
\ No newline at end of file
diff --git a/tests/lib/convert/close_test.dart b/tests/lib/convert/close_test.dart
new file mode 100644
index 0000000..541c1fa
--- /dev/null
+++ b/tests/lib/convert/close_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "dart:convert";
+
+class MySink implements Sink<List<int>> {
+ List<int> accumulated = <int>[];
+ bool isClosed = false;
+
+ add(List<int> list) {
+ accumulated.addAll(list);
+ return list.length;
+ }
+
+ close() {
+ isClosed = true;
+ // Returning a value here triggered a bug, where the caller was trying to
+ // pass the value through its 'void' return type.
+ // Example: void close() => _sink.close();
+ return "done";
+ }
+}
+
+main() {
+ var mySink = new MySink();
+ var byteSink = new ByteConversionSink.from(mySink);
+ byteSink.add([1, 2, 3]);
+ byteSink.close();
+ Expect.listEquals([1, 2, 3], mySink.accumulated);
+ Expect.isTrue(mySink.isClosed);
+}
diff --git a/tests/lib/convert/streamed_conversion_json_utf8_decode_test.dart b/tests/lib/convert/streamed_conversion_json_utf8_decode_test.dart
index 783e079..ab014ee 100644
--- a/tests/lib/convert/streamed_conversion_json_utf8_decode_test.dart
+++ b/tests/lib/convert/streamed_conversion_json_utf8_decode_test.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.
// Test write barrier verification mode.
-// VMOptions=--verified_mem --verify_before_gc --verify_after_gc --old_gen_growth_rate=1
+// VMOptions=--verify_before_gc --verify_after_gc --old_gen_growth_rate=1 --no-background-compilation
// VMOptions=
import "package:expect/expect.dart";
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 8b9fb54..c0a201e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -102,6 +102,7 @@
mirrors/variable_is_const_test/none: RuntimeError # Issue 14671
mirrors/raw_type_test/01: RuntimeError # Issue 6490
mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16589
+mirrors/regress_26187_test: RuntimeError # Issue 6490
[ $runtime == safari || $runtime == safarimobilesim ]
typed_data/int32x4_test: Fail, Pass # Safari has an optimization bug (nightlies are already fine).
@@ -361,3 +362,8 @@
[ $noopt || $compiler == precompiler ]
convert/chunked_conversion_utf88_test: Pass, Timeout
convert/utf85_test: Pass, Timeout
+
+[ $arch == simdbc || $arch == simdbc64 ]
+# TODO(vegorov) LoadField bytecode supports only up to 256 fields. Need a long
+# version.
+mirrors/accessor_cache_overflow_test: Skip
diff --git a/tests/lib/mirrors/reflected_type_function_type_test.dart b/tests/lib/mirrors/reflected_type_function_type_test.dart
index 4b7cf03..bf57c47 100644
--- a/tests/lib/mirrors/reflected_type_function_type_test.dart
+++ b/tests/lib/mirrors/reflected_type_function_type_test.dart
@@ -18,5 +18,5 @@
(reflectType(Predicate) as TypedefMirror).referent;
expectReflectedType(numToBool1, somePredicate.runtimeType);
- expectReflectedType(numToBool2, somePredicate.runtimeType);
+ expectReflectedType(numToBool2, Predicate);
}
diff --git a/tests/lib/mirrors/regress_26187_test.dart b/tests/lib/mirrors/regress_26187_test.dart
new file mode 100644
index 0000000..1d99362
--- /dev/null
+++ b/tests/lib/mirrors/regress_26187_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, 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';
+
+class A {
+ const A();
+}
+
+class B {
+ const B();
+}
+
+typedef void f(@A() int, String);
+
+typedef void g(@B() int, String);
+
+main() {
+ ParameterMirror fParamMirror = (reflectType(f) as TypedefMirror).referent.parameters[0];
+ ParameterMirror gParamMirror = (reflectType(g) as TypedefMirror).referent.parameters[0];
+ Expect.equals('.A', MirrorSystem.getName(fParamMirror.metadata[0].type.qualifiedName));
+ Expect.equals('.B', MirrorSystem.getName(gParamMirror.metadata[0].type.qualifiedName));
+}
diff --git a/tests/standalone/io/addlatexhash_test.dart b/tests/standalone/io/addlatexhash_test.dart
index 1f189ab..582b75a 100755
--- a/tests/standalone/io/addlatexhash_test.dart
+++ b/tests/standalone/io/addlatexhash_test.dart
@@ -80,12 +80,16 @@
if (dartExecutable == "") throw "dart executable not available";
// actions to take
- runAddHash() =>
- Process.runSync(dartExecutable,
- [path.join(dartRootPath, "tools", "addlatexhash.dart"),
- tmpPar8timesPath,
- hashPath,
- listPath]);
+ runAddHash() {
+ var args = [
+ '--package-root=${Platform.packageRoot}',
+ path.join(dartRootPath, "tools", "addlatexhash.dart"),
+ tmpPar8timesPath,
+ hashPath,
+ listPath
+ ];
+ return Process.runSync(dartExecutable, args);
+ }
// perform test
new File(par8timesPath).copySync(tmpPar8timesPath);
@@ -149,12 +153,16 @@
runLatex(fileName,workingDirectory) =>
Process.runSync("latex", [fileName], workingDirectory: workingDirectory);
- runAddHash() =>
- Process.runSync(dartExecutable,
- [path.join(dartRootPath, "tools", "addlatexhash.dart"),
- tmpSpecPath,
- hashPath,
- listPath]);
+ runAddHash() {
+ var args = [
+ '--package-root=${Platform.packageRoot}',
+ path.join(dartRootPath, "tools", "addlatexhash.dart"),
+ tmpSpecPath,
+ hashPath,
+ listPath
+ ];
+ return Process.runSync(dartExecutable, args);
+ }
runDvi2tty(dviFile) =>
Process.runSync("dvi2tty", [dviFile], workingDirectory: tmpDirPath);
diff --git a/tests/standalone/io/file_lock_test.dart b/tests/standalone/io/file_lock_test.dart
index d84ca2b..ca590c1 100644
--- a/tests/standalone/io/file_lock_test.dart
+++ b/tests/standalone/io/file_lock_test.dart
@@ -36,11 +36,11 @@
}
checkLocked(String path,
- [int start, int end, FileLock mode = FileLock.EXCLUSIVE]) =>
+ [int start = 0, int end = -1, FileLock mode = FileLock.EXCLUSIVE]) =>
check(path, start, end, mode, locked: true);
checkNotLocked(String path,
- [int start, int end, FileLock mode = FileLock.EXCLUSIVE]) =>
+ [int start = 0, int end = -1, FileLock mode = FileLock.EXCLUSIVE]) =>
check(path, start, end, mode, locked: false);
void testLockWholeFile() {
diff --git a/tests/standalone/io/http_auth_digest_test.dart b/tests/standalone/io/http_auth_digest_test.dart
index 5512cd0..6a902b0 100644
--- a/tests/standalone/io/http_auth_digest_test.dart
+++ b/tests/standalone/io/http_auth_digest_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 "package:convert/convert.dart";
import "package:crypto/crypto.dart";
import "package:expect/expect.dart";
import 'dart:async';
@@ -31,9 +32,8 @@
String realm = "test";
String username = "dart";
String password = "password";
- var hasher = new MD5();
- hasher.add("${username}:${realm}:${password}".codeUnits);
- ha1 = CryptoUtils.bytesToHex(hasher.close());
+ var hasher = md5.convert("${username}:${realm}:${password}".codeUnits);
+ ha1 = hex.encode(hasher.bytes);
var nonce = "12345678"; // No need for random nonce in test.
@@ -96,18 +96,17 @@
}
Expect.isNotNull(header.parameters["response"]);
- var hasher = new MD5();
- hasher.add("${request.method}:${uri}".codeUnits);
- var ha2 = CryptoUtils.bytesToHex(hasher.close());
+ var hasher = md5.convert("${request.method}:${uri}".codeUnits);
+ var ha2 = hex.encode(hasher.bytes);
var x;
- hasher = new MD5();
+ Digest digest;
if (qop == null || qop == "" || qop == "none") {
- hasher.add("$ha1:${nonce}:$ha2".codeUnits);
+ digest = md5.convert("$ha1:${nonce}:$ha2".codeUnits);
} else {
- hasher.add("$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
+ digest = md5.convert("$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
}
- Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
+ Expect.equals(hex.encode(digest.bytes),
header.parameters["response"]);
successCount++;
diff --git a/tests/standalone/io/http_auth_test.dart b/tests/standalone/io/http_auth_test.dart
index d259bdf..8433067 100644
--- a/tests/standalone/io/http_auth_test.dart
+++ b/tests/standalone/io/http_auth_test.dart
@@ -42,7 +42,7 @@
List<String> tokens = authorization.split(" ");
Expect.equals("Basic", tokens[0]);
String auth =
- CryptoUtils.bytesToBase64(UTF8.encode("$username:$password"));
+ BASE64.encode(UTF8.encode("$username:$password"));
if (passwordChanged && auth != tokens[1]) {
response.statusCode = HttpStatus.UNAUTHORIZED;
response.headers.set(HttpHeaders.WWW_AUTHENTICATE,
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
index 1d2e585..7a349d1 100644
--- a/tests/standalone/io/http_proxy_advanced_test.dart
+++ b/tests/standalone/io/http_proxy_advanced_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 "package:convert/convert.dart";
import "package:crypto/crypto.dart";
import "package:expect/expect.dart";
import "package:path/path.dart";
@@ -115,9 +116,8 @@
authScheme = "Digest";
// Calculate ha1.
- var hasher = new MD5();
- hasher.add("${username}:${realm}:${password}".codeUnits);
- ha1 = CryptoUtils.bytesToHex(hasher.close());
+ var digest = md5.convert("${username}:${realm}:${password}".codeUnits);
+ ha1 = hex.encode(digest.bytes);
}
basicAuthenticationRequired(request) {
@@ -173,7 +173,7 @@
List<String> tokens = authorization.split(" ");
Expect.equals("Basic", tokens[0]);
String auth =
- CryptoUtils.bytesToBase64(UTF8.encode("$username:$password"));
+ BASE64.encode(UTF8.encode("$username:$password"));
if (auth != tokens[1]) {
basicAuthenticationRequired(request);
return;
@@ -206,19 +206,17 @@
}
Expect.isNotNull(header.parameters["response"]);
- var hasher = new MD5();
- hasher.add("${request.method}:${uri}".codeUnits);
- var ha2 = CryptoUtils.bytesToHex(hasher.close());
+ var digest = md5.convert("${request.method}:${uri}".codeUnits);
+ var ha2 = hex.encode(digest.bytes);
var x;
- hasher = new MD5();
if (qop == null || qop == "" || qop == "none") {
- hasher.add("$ha1:${nonce}:$ha2".codeUnits);
+ digest = md5.convert("$ha1:${nonce}:$ha2".codeUnits);
} else {
- hasher.add(
+ digest = md5.convert(
"$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
}
- Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
+ Expect.equals(hex.encode(digest.bytes),
header.parameters["response"]);
// Add a bogus Proxy-Authentication-Info for testing.
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index e2505f3..70a7f8c 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.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.
+import "package:convert/convert.dart";
import "package:crypto/crypto.dart";
import "package:expect/expect.dart";
-import "package:path/path.dart";
import "dart:async";
import "dart:io";
import 'dart:convert';
@@ -109,17 +109,6 @@
authScheme = "Basic";
}
- void useDigestAuthentication(String username, String password) {
- this.username = username;
- this.password = password;
- authScheme = "Digest";
-
- // Calculate ha1.
- var hasher = new MD5();
- hasher.add("${username}:${realm}:${password}".codeUnits);
- ha1 = CryptoUtils.bytesToHex(hasher.close());
- }
-
basicAuthenticationRequired(request) {
request.fold(null, (x, y) {}).then((_) {
var response = request.response;
@@ -173,7 +162,7 @@
List<String> tokens = authorization.split(" ");
Expect.equals("Basic", tokens[0]);
String auth =
- CryptoUtils.bytesToBase64(UTF8.encode("$username:$password"));
+ BASE64.encode(UTF8.encode("$username:$password"));
if (auth != tokens[1]) {
basicAuthenticationRequired(request);
return;
@@ -206,20 +195,17 @@
}
Expect.isNotNull(header.parameters["response"]);
- var hasher = new MD5();
- hasher.add("${request.method}:${uri}".codeUnits);
- var ha2 = CryptoUtils.bytesToHex(hasher.close());
+ var digest = md5.convert("${request.method}:${uri}".codeUnits);
+ var ha2 = hex.encode(digest.bytes);
- var x;
- hasher = new MD5();
if (qop == null || qop == "" || qop == "none") {
- hasher.add("$ha1:${nonce}:$ha2".codeUnits);
+ digest = md5.convert("$ha1:${nonce}:$ha2".codeUnits);
} else {
- hasher.add(
+ digest = md5.convert(
"$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
}
- Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
- header.parameters["response"]);
+ Expect.equals(hex.encode(digest.bytes),
+ header.parameters["response"]);
// Add a bogus Proxy-Authentication-Info for testing.
var info = 'rspauth="77180d1ab3d6c9de084766977790f482", '
diff --git a/tests/standalone/io/named_pipe_script_test.dart b/tests/standalone/io/named_pipe_script_test.dart
new file mode 100644
index 0000000..83df737
--- /dev/null
+++ b/tests/standalone/io/named_pipe_script_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, 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.
+// Testing file input stream, VM-only, standalone test.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:expect/expect.dart";
+
+main() {
+ // Reading a script from a named pipe is only supported on Linux and MacOS.
+ if (!Platform.isLinux && !Platform.isMacOS) {
+ return;
+ }
+
+ final String script = 'int main() {print("Hello, World!");}';
+ final String stdinPipePath = '/dev/fd/0';
+ StringBuffer output = new StringBuffer();
+ Process.start(Platform.executable, [stdinPipePath]).then((Process process) {
+ process.stdout.transform(UTF8.decoder).listen(output.write);
+ process.stderr.transform(UTF8.decoder).listen((data) {
+ Expect.fail(data);
+ });
+ process.stdin.writeln(script);
+ process.stdin.close();
+ process.exitCode.then((int status) {
+ Expect.equals(0, status);
+ Expect.equals("Hello, World!\n", output.toString());
+ });
+ });
+}
diff --git a/tests/standalone/io/network_interface_test.dart b/tests/standalone/io/network_interface_test.dart
index 2d49ce0..71f8312 100644
--- a/tests/standalone/io/network_interface_test.dart
+++ b/tests/standalone/io/network_interface_test.dart
@@ -47,6 +47,9 @@
void main() {
+ if (!NetworkInterface.listSupported) {
+ return;
+ }
testListLoopback();
testListLinkLocal();
testListIndex();
diff --git a/tests/standalone/io/test_extension_test.dart b/tests/standalone/io/test_extension_test.dart
index 0f03233..40d768e 100644
--- a/tests/standalone/io/test_extension_test.dart
+++ b/tests/standalone/io/test_extension_test.dart
@@ -12,6 +12,7 @@
Future copyFileToDirectory(String file, String directory) {
switch (Platform.operatingSystem) {
+ case 'android':
case 'linux':
case 'macos':
return Process.run('cp', [file, directory]);
@@ -22,30 +23,67 @@
}
}
-String getExtensionPath(String buildDirectory) {
+// Returns a list containing the source file name in the first element and the
+// target file name in the second element.
+List<String> getExtensionNames(String arch) {
switch (Platform.operatingSystem) {
+ case 'android':
case 'linux':
- return join(buildDirectory, 'lib.target', 'libtest_extension.so');
+ return ['libtest_extension.so', 'libtest_extension$arch.so'];
case 'macos':
- return join(buildDirectory, 'libtest_extension.dylib');
+ return ['libtest_extension.dylib', 'libtest_extension$arch.dylib'];
case 'windows':
- return join(buildDirectory, 'test_extension.dll');
+ return ['test_extension.dll','test_extension$arch.dll'];
default:
Expect.fail('Unknown operating system ${Platform.operatingSystem}');
}
}
-void main() {
+String getExtensionPath(String buildDirectory, String filename) {
+ switch (Platform.operatingSystem) {
+ case 'android':
+ case 'linux':
+ return join(buildDirectory, 'lib.target', filename);
+ case 'macos':
+ case 'windows':
+ return join(buildDirectory, filename);
+ default:
+ Expect.fail('Unknown operating system ${Platform.operatingSystem}');
+ }
+}
+
+String getArchFromBuildDir(String buildDirectory) {
+ if (buildDirectory.endsWith('SIMARM')) return '';
+ if (buildDirectory.endsWith('SIMARM64')) return '';
+ if (buildDirectory.endsWith('SIMDBC')) return '';
+ if (buildDirectory.endsWith('SIMMIPS')) return '';
+ if (buildDirectory.endsWith('ARM')) return '-arm';
+ if (buildDirectory.endsWith('ARM64')) return '-arm64';
+ if (buildDirectory.endsWith('IA32')) return '-ia32';
+ if (buildDirectory.endsWith('MIPS')) return '-mips';
+ if (buildDirectory.endsWith('X64')) return '-x64';
+ return 'unknown';
+}
+
+Future testExtension(bool withArchSuffix) {
String scriptDirectory = dirname(Platform.script.toFilePath());
String buildDirectory = dirname(Platform.executable);
Directory tempDirectory =
Directory.systemTemp.createTempSync('dart_test_extension');
String testDirectory = tempDirectory.path;
+ List<String> fileNames;
+ if (withArchSuffix) {
+ String arch = getArchFromBuildDir(buildDirectory);
+ fileNames = getExtensionNames(arch);
+ } else {
+ fileNames = getExtensionNames('');
+ }
+
// Copy test_extension shared library, test_extension.dart and
// test_extension_tester.dart to the temporary test directory.
- copyFileToDirectory(getExtensionPath(buildDirectory),
- testDirectory).then((_) {
+ return copyFileToDirectory(getExtensionPath(buildDirectory, fileNames[0]),
+ join(testDirectory, fileNames[1])).then((_) {
var extensionDartFile = join(scriptDirectory, 'test_extension.dart');
return copyFileToDirectory(extensionDartFile, testDirectory);
}).then((_) {
@@ -69,3 +107,16 @@
tempDirectory.deleteSync(recursive: true);
});
}
+
+Future testWithArchSuffix() {
+ return testExtension(true);
+}
+
+Future testWithoutArchSuffix() {
+ return testExtension(false);
+}
+
+main() async {
+ await testWithArchSuffix();
+ await testWithoutArchSuffix();
+}
diff --git a/tests/standalone/io/web_socket_compression_test.dart b/tests/standalone/io/web_socket_compression_test.dart
index e25bc1b..99f341e 100644
--- a/tests/standalone/io/web_socket_compression_test.dart
+++ b/tests/standalone/io/web_socket_compression_test.dart
@@ -57,7 +57,7 @@
for (int i = 0; i < 16; i++) {
nonceData[i] = random.nextInt(256);
}
- String nonce = CryptoUtils.bytesToBase64(nonceData);
+ String nonce = BASE64.encode(nonceData);
uri = new Uri(
scheme: uri.scheme == "wss" ? "https" : "http",
@@ -71,7 +71,7 @@
if (uri.userInfo != null && !uri.userInfo.isEmpty) {
// If the URL contains user information use that for basic
// authorization.
- String auth = CryptoUtils.bytesToBase64(UTF8.encode(uri.userInfo));
+ String auth = BASE64.encode(UTF8.encode(uri.userInfo));
request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
}
// Setup the initial handshake.
@@ -175,8 +175,8 @@
Expect.equals('websocket', request.headers.value(HttpHeaders.UPGRADE));
var key = request.headers.value('Sec-WebSocket-Key');
- var sha1 = new SHA1()..add("$key$WEB_SOCKET_GUID".codeUnits);
- var accept = CryptoUtils.bytesToBase64(sha1.close());
+ var digest = sha1.convert("$key$WEB_SOCKET_GUID".codeUnits);
+ var accept = BASE64.encode(digest.bytes);
request.response
..statusCode = HttpStatus.SWITCHING_PROTOCOLS
..headers.add(HttpHeaders.CONNECTION, "Upgrade")
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index f7ff673..3977e84 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -13,6 +13,7 @@
import "dart:typed_data";
import "package:async_helper/async_helper.dart";
+import "package:convert/convert.dart";
import "package:crypto/crypto.dart";
import "package:expect/expect.dart";
import "package:path/path.dart";
@@ -467,8 +468,8 @@
Expect.equals('websocket', request.headers.value(HttpHeaders.UPGRADE));
var key = request.headers.value('Sec-WebSocket-Key');
- var sha1 = new SHA1()..add("$key$WEB_SOCKET_GUID".codeUnits);
- var accept = CryptoUtils.bytesToBase64(sha1.close());
+ var digest = sha1.convert("$key$WEB_SOCKET_GUID".codeUnits);
+ var accept = BASE64.encode(digest.bytes);
request.response
..statusCode = HttpStatus.SWITCHING_PROTOCOLS
..headers.add(HttpHeaders.CONNECTION, "Upgrade")
@@ -535,7 +536,7 @@
server.listen((request) {
Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request));
String auth =
- CryptoUtils.bytesToBase64(UTF8.encode(userInfo));
+ BASE64.encode(UTF8.encode(userInfo));
Expect.equals('Basic $auth', request.headers['Authorization'][0]);
Expect.equals(1, request.headers['Authorization'].length);
WebSocketTransformer.upgrade(request).then((webSocket) {
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 4103c33..46f4331 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -14,7 +14,7 @@
package/scenarios/invalid/invalid_package_name_test: RuntimeError, CompileTimeError # Errors intentionally
package/scenarios/invalid/same_package_twice_test.dart: RuntimeError, CompileTimeError # Errors intentionally
full_coverage_test: Pass, Slow, Timeout
-
+verified_mem_test: Pass, Slow, Timeout # Does verify before and after GC.
issue14236_test: Pass # Do not remove this line. It serves as a marker for Issue 14516 comment #4.
@@ -255,6 +255,7 @@
io/code_collection_test: Skip # Platform.executable
io/raw_socket_cross_process_test: Skip # Platform.executable
io/test_extension_test: Skip # Platform.executable
+io/named_pipe_script_test: Skip # Platform.executable
io/regress_7679_test: Skip # Platform.executable
io/process_*: Skip # Most use Platform.executable
assert_test: SkipByDesign # Requires checked mode.
@@ -284,3 +285,13 @@
package/scenarios/empty_packages_file/empty_packages_file_noimports_test: Skip
package/scenarios/packages_option_only/packages_option_only_noimports_test: Skip
package/scenarios/packages_option_only/packages_option_only_test: Skip
+
+[ $arch == simdbc || $arch == simdbc64 ]
+# TODO(vegorov) SIMDBC interpreter doesn't support coverage yet.
+full_coverage_test: Skip
+
+# SIMDBC interpreter doesn't support lazy linking of natives.
+link_natives_lazily_test: SkipByDesign
+
+# SIMDBC interpreter doesn't support --no_lazy_dispatchers
+no_lazy_dispatchers_test: SkipByDesign
diff --git a/tests/standalone/verified_mem_test.dart b/tests/standalone/verified_mem_test.dart
index 7139e09..53da2ca 100644
--- a/tests/standalone/verified_mem_test.dart
+++ b/tests/standalone/verified_mem_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
//
// Test write barrier verification mode.
-// VMOptions=--verified_mem --verify_before_gc --verify_after_gc --old_gen_growth_rate=1
+// VMOptions=--verify_before_gc --verify_after_gc --old_gen_growth_rate=1
var a = [];
diff --git a/tests/try/poi/apply_updates_test.dart b/tests/try/poi/apply_updates_test.dart
index e8c8429..6c7c6cd 100644
--- a/tests/try/poi/apply_updates_test.dart
+++ b/tests/try/poi/apply_updates_test.dart
@@ -40,7 +40,7 @@
Future run() => loadMainApp().then((LibraryElement library) {
// Capture the current version of [before] before invoking the [updater].
PartialFunctionElement before = library.localLookup(expectedUpdate);
- var beforeNode = before.parseNode(compiler.parsing);
+ var beforeNode = before.parseNode(compiler.parsingContext);
var context = new IncrementalCompilerContext();
LibraryUpdater updater =
@@ -56,10 +56,10 @@
// Check that the [updater] didn't modify the changed element.
Expect.identical(before, update.before);
- Expect.identical(beforeNode, before.parseNode(compiler.parsing));
+ Expect.identical(beforeNode, before.parseNode(compiler.parsingContext));
PartialFunctionElement after = update.after;
- var afterNode = after.parseNode(compiler.parsing);
+ var afterNode = after.parseNode(compiler.parsingContext);
// Check that pretty-printing the elements match [source] (before), and
// [newSource] (after).
@@ -72,7 +72,7 @@
// Check that the update was applied by pretty-printing [before]. Make no
// assumptions about [after], as the update may destroy that element.
- beforeNode = before.parseNode(compiler.parsing);
+ beforeNode = before.parseNode(compiler.parsingContext);
Expect.notEquals(source, '$beforeNode');
Expect.stringEquals(newSource, '$beforeNode');
});
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
new file mode 100644
index 0000000..dc26330
--- /dev/null
+++ b/third_party/boringssl/BUILD.gn
@@ -0,0 +1,95 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+
+# Config for us and everybody else depending on BoringSSL.
+config("external_config") {
+ include_dirs = [ "src/include" ]
+ if (is_component_build) {
+ defines = [ "BORINGSSL_SHARED_LIBRARY" ]
+ }
+}
+
+
+# Config internal to this build file, shared by boringssl and boringssl_fuzzer.
+config("internal_config") {
+ visibility = [ ":*" ] # Only targets in this file can depend on this.
+ defines = [
+ "BORINGSSL_IMPLEMENTATION",
+ "BORINGSSL_NO_STATIC_INITIALIZER",
+ "OPENSSL_SMALL_FOOTPRINT",
+ ]
+}
+
+
+config("no_asm_config") {
+ visibility = [ ":*" ] # Only targets in this file can depend on this.
+ defines = [ "OPENSSL_NO_ASM" ]
+}
+
+
+# The list of BoringSSL files is kept in boringssl.gypi.
+gypi_values =
+ exec_script("../../tools/gypi_to_gn.py",
+ [ rebase_path("boringssl.gypi") ],
+ "scope",
+ [ "boringssl.gypi" ])
+boringssl_sources =
+ gypi_values.boringssl_crypto_sources + gypi_values.boringssl_ssl_sources
+
+
+source_set("boringssl_asm") {
+ visibility = [ ":*" ] # Only targets in this file can depend on this.
+ sources = []
+ #asmflags = []
+ include_dirs = [
+ "src/include",
+ # This is for arm_arch.h, which is needed by some asm files. Since the
+ # asm files are generated and kept in a different directory, they
+ # cannot use relative paths to find this file.
+ "src/crypto",
+ ]
+
+ if (current_cpu == "x64") {
+ if (is_ios) {
+ defines += [ "OPENSSL_NO_ASM" ]
+ } else if (is_mac) {
+ sources += gypi_values.boringssl_mac_x86_64_sources
+ } else if (is_linux || is_android) {
+ sources += gypi_values.boringssl_linux_x86_64_sources
+ } else {
+ public_configs = [ ":no_asm_config" ]
+ }
+ } else if (current_cpu == "x86") {
+ if (is_ios) {
+ defines += [ "OPENSSL_NO_ASM" ]
+ } else if (is_mac) {
+ sources += gypi_values.boringssl_mac_x86_sources
+ } else if (is_linux || is_android) {
+ sources += gypi_values.boringssl_linux_x86_sources
+ } else {
+ public_configs = [ ":no_asm_config" ]
+ }
+ } else if (current_cpu == "arm" && (is_linux || is_android)) {
+ sources += gypi_values.boringssl_linux_arm_sources
+ } else if (current_cpu == "arm64" && (is_linux || is_android)) {
+ sources += gypi_values.boringssl_linux_aarch64_sources
+ } else {
+ public_configs = [ ":no_asm_config" ]
+ }
+}
+
+
+component("boringssl") {
+ sources = boringssl_sources
+ deps = [
+ ":boringssl_asm",
+ ]
+ public_configs = [ ":external_config" ]
+ configs += [ ":internal_config" ]
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/third_party/boringssl/boringssl_configurations.gypi b/third_party/boringssl/boringssl_configurations.gypi
index 0a82431..b963505 100644
--- a/third_party/boringssl/boringssl_configurations.gypi
+++ b/third_party/boringssl/boringssl_configurations.gypi
@@ -87,6 +87,13 @@
'OPENSSL_NO_ASM',
],
},
+ # Android 64-bit dbc build is for arm64, disable temporarily as well.
+ 'Dart_Android_arm64_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'OPENSSL_NO_ASM',
+ ],
+ },
# When being built for Android nss expects __linux__ to be defined.
'Dart_Android_Base': {
'target_conditions': [
diff --git a/tools/VERSION b/tools/VERSION
index da869b8..24fcc60 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
#
CHANNEL dev
MAJOR 1
-MINOR 16
+MINOR 17
PATCH 0
-PRERELEASE 5
-PRERELEASE_PATCH 5
+PRERELEASE 0
+PRERELEASE_PATCH 0
diff --git a/tools/addlatexhash.dart b/tools/addlatexhash.dart
index a8872d5..48e655c 100755
--- a/tools/addlatexhash.dart
+++ b/tools/addlatexhash.dart
@@ -11,7 +11,9 @@
// hash listing file name as the third argument. From docs/language a
// typical usage would be as follows:
//
-// dart ../../tools/addlatexhash.dart dartLangSpec.tex out.tex hash.txt
+// dart
+// --package-root=<build dir>/packages \
+// ../../tools/addlatexhash.dart dartLangSpec.tex out.tex hash.txt
//
// This will produce a normalized variant out.tex of the language
// specification with hash values filled in, and a listing hash.txt of
@@ -24,8 +26,10 @@
import 'dart:io';
import 'dart:convert';
-import '../third_party/pkg/utf/lib/utf.dart';
-import '../third_party/pkg/crypto/lib/crypto.dart';
+
+import 'package:crypto/crypto.dart';
+import 'package:convert/convert.dart';
+import 'package:utf/utf.dart';
// ----------------------------------------------------------------------
// Normalization of the text: removal or normalization of parts that
@@ -484,16 +488,15 @@
/// in [lines], stopping just before [nextIndex]. SIDE EFFECT:
/// Outputs the simplified text and its hash value to [listSink].
computeHashValue(lines, startIndex, nextIndex, listSink) {
- final hashEncoder = new SHA1();
final gatheredLine = gatherLines(lines, startIndex, nextIndex);
final simplifiedLine = simplifyLine(gatheredLine);
listSink.write(" % $simplifiedLine\n");
- hashEncoder.add(encodeUtf8(simplifiedLine));
- return hashEncoder.close();
+ var digest = sha1.convert(encodeUtf8(simplifiedLine));
+ return digest.bytes;
}
computeHashString(lines, startIndex, nextIndex, listSink) =>
- CryptoUtils.bytesToHex(computeHashValue(lines,
+ hex.encode(computeHashValue(lines,
startIndex,
nextIndex,
listSink));
diff --git a/tools/android_link.py b/tools/android_link.py
index 6efea04..7854ce4 100755
--- a/tools/android_link.py
+++ b/tools/android_link.py
@@ -48,9 +48,10 @@
link_args = sys.argv[4:]
# Check arguments.
- if target_arch not in ['arm', 'arm64', 'ia32', 'x64']:
+ if target_arch not in ['arm', 'arm64', 'ia32', 'x64', 'simdbc', 'simdbc64']:
raise Exception(sys.argv[0] +
- " first argument must be 'arm', 'arm64', 'ia32', or 'x64'")
+ " first argument must be 'arm', 'arm64', 'ia32', 'x64', "
+ "'simdbc', or 'simdbc64'")
if link_type not in ['executable', 'library', 'shared_library']:
raise Exception(sys.argv[0] +
" second argument must be 'executable' or 'library'")
@@ -77,7 +78,7 @@
# Set up the directory of the Android NDK cross-compiler toolchain.
toolchain_arch = 'arm-linux-androideabi-4.9'
- if target_arch == 'arm64':
+ if target_arch == 'arm64' or target_arch == "simdbc64":
toolchain_arch = 'aarch64-linux-android-4.9'
if target_arch == 'ia32':
toolchain_arch = 'x86-4.9'
@@ -91,7 +92,7 @@
# Set up the path to the linker executable.
android_linker = os.path.join(android_toolchain, 'arm-linux-androideabi-g++')
- if target_arch == 'arm64':
+ if target_arch == 'arm64' or target_arch == "simdbc64":
android_linker = os.path.join(
android_toolchain, 'aarch64-linux-android-c++')
if target_arch == 'ia32':
@@ -102,7 +103,7 @@
# Grab the path to libgcc.a, which we must explicitly add to the link,
# by invoking the cross-compiler with the -print-libgcc-file-name flag.
android_gcc = os.path.join(android_toolchain, 'arm-linux-androideabi-gcc')
- if target_arch == 'arm64':
+ if target_arch == 'arm64' or target_arch == "simdbc64":
android_gcc = os.path.join(android_toolchain, 'aarch64-linux-android-gcc')
if target_arch == 'ia32':
android_gcc = os.path.join(android_toolchain, 'i686-linux-android-gcc')
@@ -116,7 +117,7 @@
android_ndk_sysroot = os.path.join(android_ndk_root,
'platforms', 'android-14', 'arch-arm')
libdir = 'lib'
- if target_arch == 'arm64':
+ if target_arch == 'arm64' or target_arch == "simdbc64":
android_ndk_sysroot = os.path.join(android_ndk_root,
'platforms', 'android-21', 'arch-arm64')
if target_arch == 'ia32':
diff --git a/tools/build.py b/tools/build.py
index 3ec70d2..4b9df2a 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -56,7 +56,7 @@
result.add_option("-a", "--arch",
help='Target architectures (comma-separated).',
metavar='[all,ia32,x64,simarm,arm,simarmv6,armv6,simarmv5te,armv5te,'
- 'simmips,mips,simarm64,arm64,]',
+ 'simmips,mips,simarm64,arm64,simdbc,]',
default=utils.GuessArchitecture())
result.add_option("--os",
help='Target OSs (comma-separated).',
@@ -102,7 +102,8 @@
return False
for arch in options.arch:
archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6',
- 'simarmv5te', 'armv5te', 'simmips', 'mips', 'simarm64', 'arm64',]
+ 'simarmv5te', 'armv5te', 'simmips', 'mips', 'simarm64', 'arm64',
+ 'simdbc', 'simdbc64']
if not arch in archs:
print "Unknown arch %s" % arch
return False
@@ -119,7 +120,8 @@
print ("Cross-compilation to %s is not supported on host os %s."
% (os_name, HOST_OS))
return False
- if not arch in ['ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', 'mips']:
+ if not arch in ['ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', 'mips',
+ 'simdbc', 'simdbc64']:
print ("Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))
return False
@@ -137,9 +139,9 @@
if target_os == 'android':
android_toolchain = GetAndroidToolchainDir(HOST_OS, arch)
- if arch == 'arm':
+ if arch == 'arm' or arch == 'simdbc':
return os.path.join(android_toolchain, 'arm-linux-androideabi')
- if arch == 'arm64':
+ if arch == 'arm64' or arch == 'simdbc64':
return os.path.join(android_toolchain, 'aarch64-linux-android')
if arch == 'ia32':
return os.path.join(android_toolchain, 'i686-linux-android')
@@ -197,7 +199,7 @@
global THIRD_PARTY_ROOT
if host_os not in ['linux']:
raise Exception('Unsupported host os %s' % host_os)
- if target_arch not in ['ia32', 'x64', 'arm', 'arm64']:
+ if target_arch not in ['ia32', 'x64', 'arm', 'arm64', 'simdbc', 'simdbc64']:
raise Exception('Unsupported target architecture %s' % target_arch)
# Set up path to the Android NDK.
@@ -209,7 +211,7 @@
# Set up the directory of the Android NDK cross-compiler toolchain.
toolchain_arch = 'arm-linux-androideabi-4.9'
- if target_arch == 'arm64':
+ if target_arch == 'arm64' or target_arch == 'simdbc64':
toolchain_arch = 'aarch64-linux-android-4.9'
if target_arch == 'ia32':
toolchain_arch = 'x86-4.9'
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index 533a448..11a8cc95 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -422,6 +422,22 @@
[DartSuppress] void send(sequence<unsigned long> data, optional double timestamp);
};
+[DartSuppress]
+interface MutationEvent {};
+
+// Tweaks types required for Dart strong mode.
+[DartSupplemental]
+interface HTMLCollection {
+
+ // FIXME: The index argument should not be optional.
+ getter Node? item([Default=Undefined] optional unsigned long index);
+ getter any namedItem(DOMString name);
+
+ [DartSuppress] getter Element? item([Default=Undefined] optional unsigned long index);
+ [DartSuppress] getter Element? namedItem(DOMString name);
+
+};
+
Element implements GlobalEventHandlers;
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index 007f3f5..c66ce5b 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -587,7 +587,7 @@
inits = self._members_emitter.Emit(
'\n $(METADATA)'
'factory $CONSTRUCTOR($PARAMS) {\n'
- ' var e = $FACTORY.$CTOR_FACTORY_NAME($FACTORY_PARAMS);\n'
+ ' $CONSTRUCTOR e = $FACTORY.$CTOR_FACTORY_NAME($FACTORY_PARAMS);\n'
'$!INITS'
' return e;\n'
' }\n',
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index 6e83fd3..2bf39b6 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -114,7 +114,7 @@
'*.webkitfullscreenchange': ('fullscreenChange', 'Event'),
'*.webkitfullscreenerror': ('fullscreenError', 'Event'),
'*.wheel': ('wheel', 'WheelEvent'),
- 'AbstractWorker.error': ('error', 'ErrorEvent'),
+ 'AbstractWorker.error': ('error', 'Event'),
'AudioContext.complete': ('complete', 'Event'),
'ApplicationCache.cached': ('cached', 'Event'),
'ApplicationCache.checking': ('checking', 'Event'),
@@ -123,6 +123,7 @@
'ApplicationCache.obsolete': ('obsolete', 'Event'),
'ApplicationCache.progress': ('progress', 'ProgressEvent'),
'ApplicationCache.updateready': ('updateReady', 'Event'),
+ 'CompositorWorker.error': ('error', 'Event'),
'Document.readystatechange': ('readyStateChange', 'Event'),
'Document.securitypolicyviolation': ('securityPolicyViolation', 'SecurityPolicyViolationEvent'),
'Document.selectionchange': ('selectionChange', 'Event'),
@@ -190,6 +191,7 @@
'RTCPeerConnection.removestream': ('removeStream', 'MediaStreamEvent'),
'RTCPeerConnection.signalingstatechange': ('signalingStateChange', 'Event'),
'ScriptProcessorNode.audioprocess': ('audioProcess', 'AudioProcessingEvent'),
+ 'SharedWorker.error': ('error', 'Event'),
'SharedWorkerGlobalScope.connect': ('connect', 'Event'),
'SpeechRecognition.audioend': ('audioEnd', 'Event'),
'SpeechRecognition.audiostart': ('audioStart', 'Event'),
@@ -221,6 +223,7 @@
'Window.pageshow': ('pageShow', 'Event'),
'Window.progress': ('progress', 'Event'),
'Window.webkittransitionend': ('webkitTransitionEnd', 'TransitionEvent'),
+ 'Worker.error': ('error', 'Event'),
'XMLHttpRequestEventTarget.abort': ('abort', 'ProgressEvent'),
'XMLHttpRequestEventTarget.error': ('error', 'ProgressEvent'),
'XMLHttpRequestEventTarget.load': ('load', 'ProgressEvent'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 2712916..8b9311b 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -97,7 +97,6 @@
'HTMLFrameSetElement',
'HTMLMarqueeElement',
'IDBAny',
- 'MutationEvent',
'Notation',
'PagePopupController',
'RGBColor',
@@ -242,11 +241,14 @@
'Document.title',
'Document.webkitCancelFullScreen',
'Document.webkitExitFullscreen',
+ # Not prefixed.
'Document.webkitFullscreenElement',
'Document.webkitFullscreenEnabled',
'Document.webkitHidden',
'Document.webkitIsFullScreen',
'Document.webkitVisibilityState',
+ # Not prefixed but requires custom implementation for cross-browser compatibility.
+ 'Document.visibilityState',
'Element.animate',
'Element.children',
@@ -318,13 +320,10 @@
'MouseEvent.clientY',
'MouseEvent.movementX',
'MouseEvent.movementY',
- 'MouseEvent.webkitMovementX',
- 'MouseEvent.webkitMovementY',
'MouseEvent.offsetX',
'MouseEvent.offsetY',
'MouseEvent.screenX',
'MouseEvent.screenY',
- 'MutationEvent.initMutationEvent',
'MutationObserver.observe',
'Node.attributes',
'Node.localName',
@@ -511,6 +510,7 @@
# subclasses.
# TODO(jacobr): cleanup and augment this list.
removed_html_members = monitored.Set('htmlrenamer.removed_html_members', [
+ 'Attr.textContent', # Not needed as it is the same as Node.textContent.
'AudioBufferSourceNode.looping', # TODO(vsm): Use deprecated IDL annotation
'CSSStyleDeclaration.getPropertyCSSValue',
'CanvasRenderingContext2D.clearShadow',
@@ -768,6 +768,8 @@
'MessageEvent.data',
'MessageEvent.ports',
'MessageEvent.webkitInitMessageEvent',
+ 'MouseEvent.webkitMovementX',
+ 'MouseEvent.webkitMovementY',
'MouseEvent.x',
'MouseEvent.y',
'Navigator.registerServiceWorker',
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index efceff6..75e38fd 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -19,6 +19,21 @@
HTML_LIBRARY_NAMES = ['html', 'indexed_db', 'svg',
'web_audio', 'web_gl', 'web_sql']
+# The following two sets let us avoid shadowing fields with properties.
+# This information could be derived from the IDL files but would require
+# a significant refactor to compute accurately. Instead we manually compute
+# these sets based on manual triage of strong mode errors.
+_force_property_members = monitored.Set('systemhtml._force_property_members', [
+ 'Element.outerHtml',
+ 'Element.isContentEditable',
+ 'AudioContext.createGain',
+ 'AudioContext.createScriptProcessor',
+ ])
+_safe_to_ignore_shadowing_members = monitored.Set('systemhtml._safe_to_ignore_shadowing_members', [
+ 'SVGElement.tabIndex',
+ 'SVGStyleElement.title',
+ ])
+
_js_custom_members = monitored.Set('systemhtml._js_custom_members', [
'AudioBufferSourceNode.start',
'AudioBufferSourceNode.stop',
@@ -58,6 +73,10 @@
'Document.createTreeWalker',
'DOMException.name',
'DOMException.toString',
+ # ListMixin already provides this method although the implementation
+ # is slower. As this class is obsolete anyway, we ignore the slowdown in
+ # DOMStringList performance.
+ 'DOMStringList.contains',
'Element.animate',
'Element.createShadowRoot',
'Element.insertAdjacentElement',
@@ -891,8 +910,13 @@
# is renamed.
(super_attribute, super_attribute_interface) = self._FindShadowedAttribute(
attribute)
+ if self._ForcePropertyMember(html_name):
+ self._members_emitter.Emit('\n // Using property as subclass shadows.');
+ self._AddAttributeUsingProperties(attribute, html_name, read_only)
+ return
+
if super_attribute:
- if read_only:
+ if read_only or self._SafeToIgnoreShadowingMember(html_name):
if attribute.type.id == super_attribute.type.id:
# Compatible attribute, use the superclass property. This works
# because JavaScript will do its own dynamic dispatch.
@@ -908,6 +932,16 @@
self._AddAttributeUsingProperties(attribute, html_name, read_only)
return
+ # If the attribute is shadowed incompatibly in a subclass then we also
+ # can't just generate it as a field. In particular, this happens with
+ # DomMatrixReadOnly and its subclass DomMatrix. Force the superclass
+ # to generate getters. Hardcoding the known problem classes for now.
+ # TODO(alanknight): Fix this more generally.
+ if (self._interface.id == 'DOMMatrixReadOnly' or self._interface.id == 'DOMPointReadOnly'
+ or self._interface.id == 'DOMRectReadOnly'):
+ self._AddAttributeUsingProperties(attribute, html_name, read_only)
+ return
+
# If the type has a conversion we need a getter or setter to contain the
# conversion code.
if (self._OutputConversion(attribute.type.id, attribute.id) or
@@ -1147,6 +1181,14 @@
member_name = '%s.%s' % (self._interface.doc_js_name, member_name)
return member_name in _js_custom_members
+ def _ForcePropertyMember(self, member_name):
+ member_name = '%s.%s' % (self._interface.doc_js_name, member_name)
+ return member_name in _force_property_members
+
+ def _SafeToIgnoreShadowingMember(self, member_name):
+ member_name = '%s.%s' % (self._interface.doc_js_name, member_name)
+ return member_name in _safe_to_ignore_shadowing_members
+
def _RenamingAnnotation(self, idl_name, member_name):
if member_name != idl_name:
return "@JSName('%s')\n " % idl_name
diff --git a/tools/dom/src/AttributeMap.dart b/tools/dom/src/AttributeMap.dart
index c212a23..f72e2c3 100644
--- a/tools/dom/src/AttributeMap.dart
+++ b/tools/dom/src/AttributeMap.dart
@@ -13,7 +13,7 @@
other.forEach((k, v) { this[k] = v; });
}
- bool containsValue(String value) {
+ bool containsValue(Object value) {
for (var v in this.values) {
if (value == v) {
return true;
@@ -45,10 +45,11 @@
Iterable<String> get keys {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var keys = new List<String>();
+ var keys = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- keys.add(attributes[i].name);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ keys.add(attr.name);
}
}
return keys;
@@ -57,10 +58,11 @@
Iterable<String> get values {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var values = new List<String>();
+ var values = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- values.add(attributes[i].value);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ values.add(attr.value);
}
}
return values;
@@ -91,11 +93,11 @@
_ElementAttributeMap(Element element): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttribute(key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttribute(key);
}
@@ -103,7 +105,7 @@
_element.setAttribute(key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = _element.getAttribute(key);
_element._removeAttribute(key);
return value;
@@ -128,11 +130,11 @@
_NamespacedAttributeMap(Element element, this._namespace): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttributeNS(_namespace, key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttributeNS(_namespace, key);
}
@@ -140,7 +142,7 @@
_element.setAttributeNS(_namespace, key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = this[key];
_element._removeAttributeNS(_namespace, key);
return value;
@@ -174,11 +176,11 @@
}
// TODO: Use lazy iterator when it is available on Map.
- bool containsValue(String value) => values.any((v) => v == value);
+ bool containsValue(Object value) => values.any((v) => v == value);
- bool containsKey(String key) => _attributes.containsKey(_attr(key));
+ bool containsKey(Object key) => _attributes.containsKey(_attr(key));
- String operator [](String key) => _attributes[_attr(key)];
+ String operator [](Object key) => _attributes[_attr(key)];
void operator []=(String key, String value) {
_attributes[_attr(key)] = value;
@@ -187,7 +189,7 @@
String putIfAbsent(String key, String ifAbsent()) =>
_attributes.putIfAbsent(_attr(key), ifAbsent);
- String remove(String key) => _attributes.remove(_attr(key));
+ String remove(Object key) => _attributes.remove(_attr(key));
void clear() {
// Needs to operate on a snapshot since we are mutating the collection.
@@ -205,7 +207,7 @@
}
Iterable<String> get keys {
- final keys = new List<String>();
+ final keys = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
keys.add(_strip(key));
@@ -215,7 +217,7 @@
}
Iterable<String> get values {
- final values = new List<String>();
+ final values = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
values.add(value);
diff --git a/tools/dom/src/CrossFrameTypes.dart b/tools/dom/src/CrossFrameTypes.dart
index a923377..40af92e 100644
--- a/tools/dom/src/CrossFrameTypes.dart
+++ b/tools/dom/src/CrossFrameTypes.dart
@@ -139,7 +139,7 @@
* * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
* from WHATWG.
*/
- void postMessage(var message, String targetOrigin, [List messagePorts]);
+ void postMessage(var message, String targetOrigin, [List<MessagePort> messagePorts]);
}
abstract class LocationBase {
diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart
index 8224b77..d2334a7 100644
--- a/tools/dom/src/CssClassSet.dart
+++ b/tools/dom/src/CssClassSet.dart
@@ -41,7 +41,7 @@
* [value] must be a valid 'token' representing a single class, i.e. a
* non-empty string containing no whitespace.
*/
- bool contains(String value);
+ bool contains(Object value);
/**
* Add the class [value] to element.
@@ -93,7 +93,7 @@
* Each element of [iterable] must be a valid 'token' representing a single
* class, i.e. a non-empty string containing no whitespace.
*/
- void removeAll(Iterable<String> iterable);
+ void removeAll(Iterable<Object> iterable);
/**
* Toggles all classes specified in [iterable] on element.
diff --git a/tools/dom/src/CssRectangle.dart b/tools/dom/src/CssRectangle.dart
index 440bebe..656f853 100644
--- a/tools/dom/src/CssRectangle.dart
+++ b/tools/dom/src/CssRectangle.dart
@@ -10,7 +10,7 @@
*/
class _ContentCssRect extends CssRect {
- _ContentCssRect(element) : super(element);
+ _ContentCssRect(Element element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
@@ -31,9 +31,11 @@
if (newHeight is Dimension) {
if (newHeight.value < 0) newHeight = new Dimension.px(0);
_element.style.height = newHeight.toString();
- } else {
+ } else if (newHeight is num) {
if (newHeight < 0) newHeight = 0;
_element.style.height = '${newHeight}px';
+ } else {
+ throw new ArgumentError("newHeight is not a Dimension or num");
}
}
@@ -49,9 +51,11 @@
if (newWidth is Dimension) {
if (newWidth.value < 0) newWidth = new Dimension.px(0);
_element.style.width = newWidth.toString();
- } else {
+ } else if (newWidth is num) {
if (newWidth < 0) newWidth = 0;
_element.style.width = '${newWidth}px';
+ } else {
+ throw new ArgumentError("newWidth is not a Dimension or num");
}
}
@@ -68,7 +72,7 @@
class _ContentCssListRect extends _ContentCssRect {
List<Element> _elementList;
- _ContentCssListRect(elementList) : super(elementList.first) {
+ _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
_elementList = elementList;
}
@@ -157,10 +161,10 @@
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
-abstract class CssRect extends MutableRectangle<num> {
+abstract class CssRect implements Rectangle<num> {
Element _element;
- CssRect(this._element) : super(0, 0, 0, 0);
+ CssRect(this._element);
num get left;
@@ -253,6 +257,102 @@
}
return val;
}
+
+ // TODO(jacobr): these methods are duplicated from _RectangleBase in dart:math
+ // Ideally we would provide a RectangleMixin class that provides this implementation.
+ // In an ideal world we would exp
+ /** The x-coordinate of the right edge. */
+ num get right => left + width;
+ /** The y-coordinate of the bottom edge. */
+ num get bottom => top + height;
+
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is !Rectangle) return false;
+ return left == other.left && top == other.top && right == other.right &&
+ bottom == other.bottom;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
+ right.hashCode, bottom.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
+ */
+ Rectangle<num> intersection(Rectangle<num> other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle<num>(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle<num> boundingBox(Rectangle<num> other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle<num>(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point<num> get topLeft => new Point<num>(this.left, this.top);
+ Point<num> get topRight => new Point<num>(this.left + this.width, this.top);
+ Point<num> get bottomRight => new Point<num>(this.left + this.width,
+ this.top + this.height);
+ Point<num> get bottomLeft => new Point<num>(this.left,
+ this.top + this.height);
}
final _HEIGHT = ['top', 'bottom'];
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 3b41f51..76bed57 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -34,7 +34,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
- new _EventStream(e, _eventType, useCapture);
+ new _EventStream<T>(e, _eventType, useCapture);
/**
* Gets an [ElementEventStream] for this event type, on the specified element.
@@ -58,7 +58,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -129,8 +129,8 @@
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
@@ -144,6 +144,11 @@
}
}
+bool _matchesWithAncestors(Event event, String selector) {
+ var target = event.target;
+ return target is Element ? target.matchesWithAncestors(selector) : false;
+}
+
/**
* Adapter for exposing DOM Element events as streams, while also allowing
* event delegation.
@@ -154,7 +159,7 @@
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -178,7 +183,7 @@
this._targetList, this._eventType, this._useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -188,37 +193,46 @@
{ Function onError,
void onDone(),
bool cancelOnError}) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, _useCapture));
+ pool.add(new _EventStream<T>(target, _eventType, _useCapture));
}
return pool.stream.listen(onData, onError: onError, onDone: onDone,
cancelOnError: cancelOnError);
}
StreamSubscription<T> capture(void onData(T event)) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, true));
+ pool.add(new _EventStream<T>(target, _eventType, true));
}
return pool.stream.listen(onData);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
}
+// We would like this to just be EventListener<T> but that typdef cannot
+// use generics until dartbug/26276 is fixed.
+typedef _EventListener<T extends Event>(T event);
+
class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
int _pauseCount = 0;
EventTarget _target;
final String _eventType;
- var _onData;
+ EventListener _onData;
final bool _useCapture;
- _EventStreamSubscription(this._target, this._eventType, onData,
- this._useCapture) : _onData = _wrapZone(onData) {
+ // TODO(jacobr): for full strong mode correctness we should write
+ // _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((e) => onData(e as T))
+ // but that breaks 114 co19 tests as well as multiple html tests as it is reasonable
+ // to pass the wrong type of event object to an event listener as part of a
+ // test.
+ _EventStreamSubscription(this._target, this._eventType, void onData(T event),
+ this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@@ -240,8 +254,7 @@
}
// Remove current event listener.
_unlisten();
-
- _onData = _wrapZone(handleData);
+ _onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@@ -320,8 +333,8 @@
onDone: onDone, cancelOnError: cancelOnError);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> _streamController.stream;
bool get isBroadcast => true;
@@ -412,16 +425,16 @@
const _CustomEventStreamProvider(this._eventTypeGetter);
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
- return new _EventStream(e, _eventTypeGetter(e), useCapture);
+ return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> _forElementList(ElementList e,
{bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
String getEventType(EventTarget target) {
diff --git a/tools/dom/src/KeyboardEventStream.dart b/tools/dom/src/KeyboardEventStream.dart
index 520ac87..39c5cfc 100644
--- a/tools/dom/src/KeyboardEventStream.dart
+++ b/tools/dom/src/KeyboardEventStream.dart
@@ -16,7 +16,7 @@
* The set of keys that have been pressed down without seeing their
* corresponding keyup event.
*/
- final List<KeyboardEvent> _keyDownList = <KeyboardEvent>[];
+ final List<KeyEvent> _keyDownList = <KeyEvent>[];
/** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
final String _type;
@@ -75,8 +75,9 @@
* General constructor, performs basic initialization for our improved
* KeyboardEvent controller.
*/
- _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
+ _KeyboardEventHandler(this._type):
+ _stream = new _CustomKeyEventStreamImpl('event'), _target = null,
+ super(_EVENT_TYPE);
/**
* Hook up all event listeners under the covers so we can estimate keycodes
diff --git a/tools/dom/src/NodeValidatorBuilder.dart b/tools/dom/src/NodeValidatorBuilder.dart
index 24f079b..bcf807c 100644
--- a/tools/dom/src/NodeValidatorBuilder.dart
+++ b/tools/dom/src/NodeValidatorBuilder.dart
@@ -4,7 +4,6 @@
part of dart.dom.html;
-
/**
* Class which helps construct standard node validation policies.
*
@@ -22,11 +21,9 @@
* appropriate.
*/
class NodeValidatorBuilder implements NodeValidator {
-
final List<NodeValidator> _validators = <NodeValidator>[];
- NodeValidatorBuilder() {
- }
+ NodeValidatorBuilder() {}
/**
* Creates a new NodeValidatorBuilder which accepts common constructs.
@@ -155,29 +152,17 @@
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
+ var attrs = attributes
+ ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
if (uriPolicy == null) {
uriPolicy = new UriPolicy();
}
add(new _CustomElementNodeValidator(
- uriPolicy,
- [tagNameUpper],
- attrs,
- uriAttrs,
- false,
- true));
+ uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
}
/**
@@ -192,37 +177,26 @@
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var baseNameUpper = baseName.toUpperCase();
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
+ var attrs = attributes
+ ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
if (uriPolicy == null) {
uriPolicy = new UriPolicy();
}
- add(new _CustomElementNodeValidator(
- uriPolicy,
- [tagNameUpper, baseNameUpper],
- attrs,
- uriAttrs,
- true,
- false));
+ add(new _CustomElementNodeValidator(uriPolicy,
+ [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
}
- void allowElement(String tagName, {UriPolicy uriPolicy,
- Iterable<String> attributes,
- Iterable<String> uriAttributes}) {
-
- allowCustomElement(tagName, uriPolicy: uriPolicy,
+ void allowElement(String tagName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ allowCustomElement(tagName,
+ uriPolicy: uriPolicy,
attributes: attributes,
uriAttributes: uriAttributes);
}
@@ -253,8 +227,8 @@
}
bool allowsAttribute(Element element, String attributeName, String value) {
- return _validators.any(
- (v) => v.allowsAttribute(element, attributeName, value));
+ return _validators
+ .any((v) => v.allowsAttribute(element, attributeName, value));
}
}
@@ -265,76 +239,70 @@
final UriPolicy uriPolicy;
factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
- return new _SimpleNodeValidator(uriPolicy,
- allowedElements: const [
- 'A',
- 'FORM'],
- allowedAttributes: const [
- 'A::accesskey',
- 'A::coords',
- 'A::hreflang',
- 'A::name',
- 'A::shape',
- 'A::tabindex',
- 'A::target',
- 'A::type',
- 'FORM::accept',
- 'FORM::autocomplete',
- 'FORM::enctype',
- 'FORM::method',
- 'FORM::name',
- 'FORM::novalidate',
- 'FORM::target',
- ],
- allowedUriAttributes: const [
- 'A::href',
- 'FORM::action',
- ]);
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'A',
+ 'FORM'
+ ], allowedAttributes: const [
+ 'A::accesskey',
+ 'A::coords',
+ 'A::hreflang',
+ 'A::name',
+ 'A::shape',
+ 'A::tabindex',
+ 'A::target',
+ 'A::type',
+ 'FORM::accept',
+ 'FORM::autocomplete',
+ 'FORM::enctype',
+ 'FORM::method',
+ 'FORM::name',
+ 'FORM::novalidate',
+ 'FORM::target',
+ ], allowedUriAttributes: const [
+ 'A::href',
+ 'FORM::action',
+ ]);
}
factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
- return new _SimpleNodeValidator(uriPolicy,
- allowedElements: const [
- 'IMG'
- ],
- allowedAttributes: const [
- 'IMG::align',
- 'IMG::alt',
- 'IMG::border',
- 'IMG::height',
- 'IMG::hspace',
- 'IMG::ismap',
- 'IMG::name',
- 'IMG::usemap',
- 'IMG::vspace',
- 'IMG::width',
- ],
- allowedUriAttributes: const [
- 'IMG::src',
- ]);
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'IMG'
+ ], allowedAttributes: const [
+ 'IMG::align',
+ 'IMG::alt',
+ 'IMG::border',
+ 'IMG::height',
+ 'IMG::hspace',
+ 'IMG::ismap',
+ 'IMG::name',
+ 'IMG::usemap',
+ 'IMG::vspace',
+ 'IMG::width',
+ ], allowedUriAttributes: const [
+ 'IMG::src',
+ ]);
}
factory _SimpleNodeValidator.allowTextElements() {
- return new _SimpleNodeValidator(null,
- allowedElements: const [
- 'B',
- 'BLOCKQUOTE',
- 'BR',
- 'EM',
- 'H1',
- 'H2',
- 'H3',
- 'H4',
- 'H5',
- 'H6',
- 'HR',
- 'I',
- 'LI',
- 'OL',
- 'P',
- 'SPAN',
- 'UL',
- ]);
+ return new _SimpleNodeValidator(null, allowedElements: const [
+ 'B',
+ 'BLOCKQUOTE',
+ 'BR',
+ 'EM',
+ 'H1',
+ 'H2',
+ 'H3',
+ 'H4',
+ 'H5',
+ 'H6',
+ 'HR',
+ 'I',
+ 'LI',
+ 'OL',
+ 'P',
+ 'SPAN',
+ 'UL',
+ ]);
}
/**
@@ -343,15 +311,16 @@
* lowercase attribute name. For example `'IMG:src'`.
*/
_SimpleNodeValidator(this.uriPolicy,
- {Iterable<String> allowedElements, Iterable<String> allowedAttributes,
- Iterable<String> allowedUriAttributes}) {
+ {Iterable<String> allowedElements,
+ Iterable<String> allowedAttributes,
+ Iterable<String> allowedUriAttributes}) {
this.allowedElements.addAll(allowedElements ?? const []);
allowedAttributes = allowedAttributes ?? const [];
allowedUriAttributes = allowedUriAttributes ?? const [];
- var legalAttributes = allowedAttributes.where(
- (x) => !_Html5NodeValidator._uriAttributes.contains(x));
- var extraUriAttributes = allowedAttributes.where(
- (x) => _Html5NodeValidator._uriAttributes.contains(x));
+ var legalAttributes = allowedAttributes
+ .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
+ var extraUriAttributes = allowedAttributes
+ .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
this.allowedAttributes.addAll(legalAttributes);
this.allowedUriAttributes.addAll(allowedUriAttributes);
this.allowedUriAttributes.addAll(extraUriAttributes);
@@ -384,19 +353,19 @@
final bool allowTypeExtension;
final bool allowCustomTag;
- _CustomElementNodeValidator(UriPolicy uriPolicy,
+ _CustomElementNodeValidator(
+ UriPolicy uriPolicy,
Iterable<String> allowedElements,
Iterable<String> allowedAttributes,
Iterable<String> allowedUriAttributes,
bool allowTypeExtension,
- bool allowCustomTag):
-
- super(uriPolicy,
- allowedElements: allowedElements,
- allowedAttributes: allowedAttributes,
- allowedUriAttributes: allowedUriAttributes),
- this.allowTypeExtension = allowTypeExtension == true,
- this.allowCustomTag = allowCustomTag == true;
+ bool allowCustomTag)
+ : this.allowTypeExtension = allowTypeExtension == true,
+ this.allowCustomTag = allowCustomTag == true,
+ super(uriPolicy,
+ allowedElements: allowedElements,
+ allowedAttributes: allowedAttributes,
+ allowedUriAttributes: allowedUriAttributes);
bool allowsElement(Element element) {
if (allowTypeExtension) {
@@ -406,12 +375,14 @@
allowedElements.contains(Element._safeTagName(element));
}
}
- return allowCustomTag && allowedElements.contains(Element._safeTagName(element));
+ return allowCustomTag &&
+ allowedElements.contains(Element._safeTagName(element));
}
bool allowsAttribute(Element element, String attributeName, String value) {
- if (allowsElement(element)) {
- if (allowTypeExtension && attributeName == 'is' &&
+ if (allowsElement(element)) {
+ if (allowTypeExtension &&
+ attributeName == 'is' &&
allowedElements.contains(value.toUpperCase())) {
return true;
}
@@ -422,19 +393,22 @@
}
class _TemplatingNodeValidator extends _SimpleNodeValidator {
- static const _TEMPLATE_ATTRS =
- const <String>['bind', 'if', 'ref', 'repeat', 'syntax'];
+ static const _TEMPLATE_ATTRS = const <String>[
+ 'bind',
+ 'if',
+ 'ref',
+ 'repeat',
+ 'syntax'
+ ];
final Set<String> _templateAttrs;
- _TemplatingNodeValidator():
- super(null,
- allowedElements: [
- 'TEMPLATE'
- ],
- allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')),
- _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
- }
+ _TemplatingNodeValidator()
+ : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
+ super(null,
+ allowedElements: ['TEMPLATE'],
+ allowedAttributes:
+ _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
bool allowsAttribute(Element element, String attributeName, String value) {
if (super.allowsAttribute(element, attributeName, value)) {
@@ -445,14 +419,13 @@
return true;
}
- if (element.attributes['template'] == "" ) {
+ if (element.attributes['template'] == "") {
return _templateAttrs.contains(attributeName);
}
return false;
}
}
-
class _SvgNodeValidator implements NodeValidator {
bool allowsElement(Element element) {
if (element is svg.ScriptElement) {
@@ -462,7 +435,8 @@
// foreignobject tag as SvgElement. We don't want foreignobject contents
// anyway, so just remove the whole tree outright. And we can't rely
// on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
- if (element is svg.SvgElement && Element._safeTagName(element) == 'foreignObject') {
+ if (element is svg.SvgElement &&
+ Element._safeTagName(element) == 'foreignObject') {
return false;
}
if (element is svg.SvgElement) {
diff --git a/tools/dom/src/WrappedList.dart b/tools/dom/src/WrappedList.dart
index fd3ca95..c06e8dc 100644
--- a/tools/dom/src/WrappedList.dart
+++ b/tools/dom/src/WrappedList.dart
@@ -10,7 +10,7 @@
*/
class _WrappedList<E extends Node> extends ListBase<E>
implements NodeListWrapper {
- final List _list;
+ final List<Node> _list;
_WrappedList(this._list);
@@ -30,13 +30,13 @@
// List APIs
- E operator [](int index) => _list[index];
+ E operator [](int index) => _downcast/*<Node, E>*/(_list[index]);
void operator []=(int index, E value) { _list[index] = value; }
set length(int newLength) { _list.length = newLength; }
- void sort([int compare(E a, E b)]) { _list.sort(compare); }
+ void sort([int compare(E a, E b)]) { _list.sort((Node a, Node b) => compare(_downcast/*<Node, E>*/(a), _downcast/*<Node, E>*/(b))); }
int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
@@ -44,7 +44,7 @@
void insert(int index, E element) => _list.insert(index, element);
- E removeAt(int index) => _list.removeAt(index);
+ E removeAt(int index) => _downcast/*<Node, E>*/(_list.removeAt(index));
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_list.setRange(start, end, iterable, skipCount);
@@ -66,8 +66,8 @@
/**
* Iterator wrapper for _WrappedList.
*/
-class _WrappedIterator<E> implements Iterator<E> {
- Iterator _iterator;
+class _WrappedIterator<E extends Node> implements Iterator<E> {
+ Iterator<Node> _iterator;
_WrappedIterator(this._iterator);
@@ -75,5 +75,8 @@
return _iterator.moveNext();
}
- E get current => _iterator.current;
+ E get current => _downcast/*<Node, E>*/(_iterator.current);
}
+
+// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
+/*=To*/ _downcast/*<From, To extends From>*/(dynamic /*=From*/ x) => x;
diff --git a/tools/dom/src/dart2js_CssClassSet.dart b/tools/dom/src/dart2js_CssClassSet.dart
index 8d483b3..087685f 100644
--- a/tools/dom/src/dart2js_CssClassSet.dart
+++ b/tools/dom/src/dart2js_CssClassSet.dart
@@ -120,11 +120,11 @@
_addAll(_element, iterable);
}
- void removeAll(Iterable<String> iterable) {
+ void removeAll(Iterable<Object> iterable) {
_removeAll(_element, iterable);
}
- void retainAll(Iterable<String> iterable) {
+ void retainAll(Iterable<Object> iterable) {
_removeWhere(_element, iterable.toSet().contains, false);
}
diff --git a/tools/dom/src/dart2js_DOMImplementation.dart b/tools/dom/src/dart2js_DOMImplementation.dart
index 24e6a6c..81e9d6d 100644
--- a/tools/dom/src/dart2js_DOMImplementation.dart
+++ b/tools/dom/src/dart2js_DOMImplementation.dart
@@ -57,7 +57,7 @@
Events get on => throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
- void _addEventListener([String type, EventListener listener, bool useCapture])
+ void _addEventListener(String type, EventListener listener, [bool useCapture])
=> throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
@@ -68,8 +68,8 @@
bool dispatchEvent(Event event) => throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
- void _removeEventListener([String type, EventListener listener,
- bool useCapture]) => throw new UnsupportedError(
+ void _removeEventListener(String type, EventListener listener,
+ [bool useCapture]) => throw new UnsupportedError(
'You can only attach EventListeners to your own window.');
// TODO(efortuna): Remove this method. dartbug.com/16814
void removeEventListener(String type, EventListener listener,
diff --git a/tools/dom/src/dart2js_WrappedEvent.dart b/tools/dom/src/dart2js_WrappedEvent.dart
index 3f8789f..8508b3e 100644
--- a/tools/dom/src/dart2js_WrappedEvent.dart
+++ b/tools/dom/src/dart2js_WrappedEvent.dart
@@ -59,8 +59,8 @@
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
' not arise as a result of event delegation.');
}
- var currentTarget = this.currentTarget;
- var target = this.target;
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
var matchedTarget;
do {
if (target.matches(_selector)) return target;
diff --git a/tools/dom/src/shared_html.dart b/tools/dom/src/shared_html.dart
index b6c9c62c..27fa2b7 100644
--- a/tools/dom/src/shared_html.dart
+++ b/tools/dom/src/shared_html.dart
@@ -4,17 +4,25 @@
part of dart.dom.html;
-_wrapZone(callback(arg)) {
+// TODO(jacobr): remove these typedefs when dart:async supports generic types.
+typedef R _wrapZoneCallback<A, R>(A a);
+typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
+
+_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ callback) {
// For performance reasons avoid wrapping if we are in the root zone.
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindUnaryCallback(callback, runGuarded: true);
+ // TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindUnaryCallback(callback, runGuarded: true) as _wrapZoneCallback/*<A, R>*/;
}
-_wrapBinaryZone(callback(arg1, arg2)) {
+_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindBinaryCallback(callback, runGuarded: true);
+ // We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindBinaryCallback(callback, runGuarded: true) as _wrapZoneBinaryCallback/*<A, B, R>*/;
}
/**
diff --git a/tools/dom/templates/html/dart2js/impl_KeyboardEvent.darttemplate b/tools/dom/templates/html/dart2js/impl_KeyboardEvent.darttemplate
index bbd6aeb..0cea803 100644
--- a/tools/dom/templates/html/dart2js/impl_KeyboardEvent.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_KeyboardEvent.darttemplate
@@ -14,15 +14,15 @@
*/
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
- /**
- * Programmatically create a KeyboardEvent.
+ /**
+ * Programmatically create a KeyboardEvent.
*
* Due to browser differences, keyCode, charCode, or keyIdentifier values
* cannot be specified in this base level constructor. This constructor
* enables the user to programmatically create and dispatch a [KeyboardEvent],
* but it will not contain any particular key content. For programmatically
* creating keyboard events with specific key value contents, see the custom
- * Event [KeyEvent].
+ * Event [KeyEvent].
*/
factory $CLASSNAME(String type,
{Window view, bool canBubble: true, bool cancelable: true,
@@ -31,7 +31,7 @@
if (view == null) {
view = window;
}
- final e = document._createEvent("KeyboardEvent");
+ KeyboardEvent e = document._createEvent("KeyboardEvent");
e._initKeyboardEvent(type, canBubble, cancelable, view, "",
keyLocation, ctrlKey, altKey, shiftKey, metaKey);
return e;
diff --git a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
index 5d5d23a..8077fb0 100644
--- a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
@@ -14,7 +14,7 @@
if (view == null) {
view = window;
}
- var event = document._createEvent('MouseEvent');
+ MouseEvent event = document._createEvent('MouseEvent');
event._initMouseEvent(type, canBubble, cancelable, view, detail,
screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
button, relatedTarget);
@@ -29,9 +29,9 @@
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_webkitMovementX, _webkitMovementY);
+ Point get movement => new Point(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
diff --git a/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate b/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate
index c4dc511..1b2bbc8 100644
--- a/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate
+++ b/tools/dom/templates/html/dartium/impl_MouseEvent.darttemplate
@@ -48,9 +48,9 @@
@DomName('MouseEvent.movementX')
@DomName('MouseEvent.movementY')
@SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
@Experimental()
- Point get movement => new Point(_webkitMovementX, _webkitMovementY);
+ Point get movement => new Point(_movementX, _movementY);
/**
* The coordinates of the mouse pointer in target node coordinates.
diff --git a/tools/dom/templates/html/impl/impl_CompositionEvent.darttemplate b/tools/dom/templates/html/impl/impl_CompositionEvent.darttemplate
index 83b13b2..5b3d391 100644
--- a/tools/dom/templates/html/impl/impl_CompositionEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CompositionEvent.darttemplate
@@ -13,7 +13,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("CompositionEvent");
+ CompositionEvent e = document._createEvent("CompositionEvent");
$if DART2JS
if (Device.isFirefox) {
diff --git a/tools/dom/templates/html/impl/impl_DeviceOrientationEvent.darttemplate b/tools/dom/templates/html/impl/impl_DeviceOrientationEvent.darttemplate
index 6f452c9..6b4a4f8 100644
--- a/tools/dom/templates/html/impl/impl_DeviceOrientationEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DeviceOrientationEvent.darttemplate
@@ -9,7 +9,7 @@
factory $CLASSNAME(String type,
{bool canBubble: true, bool cancelable: true, num alpha: 0, num beta: 0,
num gamma: 0, bool absolute: false}) {
- var e = document._createEvent("DeviceOrientationEvent");
+ DeviceOrientationEvent e = document._createEvent("DeviceOrientationEvent");
e._initDeviceOrientationEvent(type, canBubble, cancelable, alpha, beta,
gamma, absolute);
return e;
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index 9dae6c7..7c8a124 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -25,9 +25,8 @@
* For details about CSS selector syntax, see the
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
- ElementList<Element> querySelectorAll(String selectors) {
- return new _FrozenElementList._wrap(_querySelectorAll(selectors));
- }
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
/**
* Alias for [querySelector]. Note this function is deprecated because its
@@ -45,7 +44,7 @@
@deprecated
@Experimental()
@DomName('Document.querySelectorAll')
- ElementList<Element> queryAll(String relativeSelectors) =>
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
querySelectorAll(relativeSelectors);
/// Checks if [registerElement] is supported on the current platform.
@@ -115,4 +114,17 @@
=> JS('TreeWalker', '#.createTreeWalker(#, #, #, false)',
this, root, whatToShow, filter);
$endif
+
+ @DomName('Document.visibilityState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @Experimental()
+$if DART2JS
+ String get visibilityState => JS('String',
+ '(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
+ '#.webkitVisibilityState)', this, this, this, this);
+$else
+ String get visibilityState => _visibilityState;
+$endif
}
diff --git a/tools/dom/templates/html/impl/impl_DocumentFragment.darttemplate b/tools/dom/templates/html/impl/impl_DocumentFragment.darttemplate
index dd4d70b..6627f0b 100644
--- a/tools/dom/templates/html/impl/impl_DocumentFragment.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DocumentFragment.darttemplate
@@ -40,7 +40,7 @@
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -57,8 +57,9 @@
* For details about CSS selector syntax, see the
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
- ElementList<Element> querySelectorAll(String selectors) =>
- new _FrozenElementList._wrap(_querySelectorAll(selectors));
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
+
String get innerHtml {
final e = new Element.tag("div");
@@ -115,8 +116,7 @@
@deprecated
@Experimental()
@DomName('DocumentFragment.querySelectorAll')
- ElementList<Element> queryAll(String relativeSelectors) {
- return querySelectorAll(relativeSelectors);
- }
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
+ querySelectorAll(relativeSelectors);
$!MEMBERS
}
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 399e90d..c9ef54a 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -71,7 +71,7 @@
_filter(test, true);
}
- void _filter(bool test(var element), bool retainMatching) {
+ void _filter(bool test(Element element), bool retainMatching) {
var removed;
if (retainMatching) {
removed = _element.children.where((e) => !test(e));
@@ -264,8 +264,8 @@
// declared to return `ElementList`. This provides all the static analysis
// benefit so there is no need for this class have a constrained type parameter.
//
-class _FrozenElementList extends ListBase
- implements ElementList, NodeListWrapper {
+class _FrozenElementList<E extends Element> extends ListBase<E>
+ implements ElementList<E>, NodeListWrapper {
final List<Node> _nodeList;
$if JSINTEROP
@@ -280,9 +280,9 @@
int get length => _nodeList.length;
- Element operator [](int index) => _nodeList[index];
+ E operator [](int index) => _downcast/*<Node, E>*/(_nodeList[index]);
- void operator []=(int index, Element value) {
+ void operator []=(int index, E value) {
throw new UnsupportedError('Cannot modify list');
}
@@ -290,7 +290,7 @@
throw new UnsupportedError('Cannot modify list');
}
- void sort([Comparator<Element> compare]) {
+ void sort([Comparator<E> compare]) {
throw new UnsupportedError('Cannot sort list');
}
@@ -298,11 +298,11 @@
throw new UnsupportedError('Cannot shuffle list');
}
- Element get first => _nodeList.first;
+ E get first => _downcast/*<Node, E>*/(_nodeList.first);
- Element get last => _nodeList.last;
+ E get last => _downcast/*<Node, E>*/(_nodeList.last);
- Element get single => _nodeList.single;
+ E get single => _downcast/*<Node, E>*/(_nodeList.single);
CssClassSet get classes => new _MultiElementCssClassSet(this);
@@ -316,7 +316,7 @@
//
// as the code below converts the Iterable[value] to a string multiple
// times. Maybe compute the string and set className here.
- _nodeList.forEach((e) => e.classes = value);
+ forEach((e) => e.classes = value);
}
CssRect get contentEdge => new _ContentCssListRect(this);
@@ -593,7 +593,7 @@
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -611,8 +611,8 @@
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
*/
@DomName('Element.querySelectorAll')
- ElementList<Element> querySelectorAll(String selectors) =>
- new _FrozenElementList._wrap(_querySelectorAll(selectors));
+ ElementList<Element /*=T*/> querySelectorAll/*<T extends Element>*/(String selectors) =>
+ new _FrozenElementList/*<T>*/._wrap(_querySelectorAll(selectors));
/**
* Alias for [querySelector]. Note this function is deprecated because its
@@ -630,7 +630,7 @@
@deprecated
@DomName('Element.querySelectorAll')
@Experimental()
- ElementList<Element> queryAll(String relativeSelectors) =>
+ ElementList<Element /*=T*/> queryAll/*<T extends Element>*/(String relativeSelectors) =>
querySelectorAll(relativeSelectors);
/**
@@ -828,19 +828,18 @@
throw new ArgumentError("The frames parameter should be a List of Maps "
"with frame information");
}
- var convertedFrames = frames;
- if (convertedFrames is Iterable) {
+ var convertedFrames;
+ if (frames is Iterable) {
$if DART2JS
convertedFrames = frames.map(convertDartToNative_Dictionary).toList();
$else
convertedFrames = convertDartToNative_List(
frames.map(convertDartToNative_Dictionary).toList());
$endif
+ } else {
+ convertedFrames = frames;
}
- var convertedTiming = timing;
- if (convertedTiming is Map) {
- convertedTiming = convertDartToNative_Dictionary(convertedTiming);
- }
+ var convertedTiming = timing is Map ? convertDartToNative_Dictionary(timing) : timing;
return convertedTiming == null
? _animate(convertedFrames)
: _animate(convertedFrames, convertedTiming);
@@ -1333,7 +1332,7 @@
// Workaround for Safari bug. Was also previously Chrome bug 229142
// - URIs are not resolved in new doc.
- var base = _parseDocument.createElement('base');
+ BaseElement base = _parseDocument.createElement('base');
base.href = document.baseUri;
_parseDocument.head.append(base);
}
diff --git a/tools/dom/templates/html/impl/impl_Event.darttemplate b/tools/dom/templates/html/impl/impl_Event.darttemplate
index e4c6e4e..9ff5f48 100644
--- a/tools/dom/templates/html/impl/impl_Event.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Event.darttemplate
@@ -33,7 +33,7 @@
e._initEvent(name, canBubble, cancelable);
return e;
}
-
+
/** The CSS selector involved with event delegation. */
String _selector;
@@ -47,8 +47,8 @@
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
' not arise as a result of event delegation.');
}
- var currentTarget = this.currentTarget;
- var target = this.target;
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
var matchedTarget;
do {
if (target.matches(_selector)) return target;
diff --git a/tools/dom/templates/html/impl/impl_EventTarget.darttemplate b/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
index 61092fd..c6d74ef 100644
--- a/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
+++ b/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
@@ -52,26 +52,24 @@
}
class ElementEvents extends Events {
- /* Raw event target. */
- final Element _ptr;
static final webkitEvents = {
- 'animationend' : 'webkitAnimationEnd',
- 'animationiteration' : 'webkitAnimationIteration',
- 'animationstart' : 'webkitAnimationStart',
- 'fullscreenchange' : 'webkitfullscreenchange',
+ 'animationend' : 'webkitAnimationEnd',
+ 'animationiteration' : 'webkitAnimationIteration',
+ 'animationstart' : 'webkitAnimationStart',
+ 'fullscreenchange' : 'webkitfullscreenchange',
'fullscreenerror' : 'webkitfullscreenerror',
- 'keyadded' : 'webkitkeyadded',
- 'keyerror' : 'webkitkeyerror',
- 'keymessage' : 'webkitkeymessage',
- 'needkey' : 'webkitneedkey',
- 'pointerlockchange' : 'webkitpointerlockchange',
- 'pointerlockerror' : 'webkitpointerlockerror',
- 'resourcetimingbufferfull' : 'webkitresourcetimingbufferfull',
+ 'keyadded' : 'webkitkeyadded',
+ 'keyerror' : 'webkitkeyerror',
+ 'keymessage' : 'webkitkeymessage',
+ 'needkey' : 'webkitneedkey',
+ 'pointerlockchange' : 'webkitpointerlockchange',
+ 'pointerlockerror' : 'webkitpointerlockerror',
+ 'resourcetimingbufferfull' : 'webkitresourcetimingbufferfull',
'transitionend': 'webkitTransitionEnd',
'speechchange' : 'webkitSpeechChange'
};
- ElementEvents(Element ptr) : this._ptr = ptr, super(ptr);
+ ElementEvents(Element ptr) : super(ptr);
Stream operator [](String type) {
if (webkitEvents.keys.contains(type.toLowerCase())) {
diff --git a/tools/dom/templates/html/impl/impl_Geolocation.darttemplate b/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
index 5518815..e1c84ac 100644
--- a/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
@@ -52,7 +52,10 @@
}
int watchId;
- var controller;
+ // TODO(jacobr): it seems like a bug that we have to specifiy the static
+ // type here for controller.stream to have the right type.
+ // dartbug.com/26278
+ StreamController<Geoposition> controller;
controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index 1264edc..4a95f9a 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -127,65 +127,6 @@
_webkitExitFullscreen();
}
- /**
- * Returns the element, if any, that is currently displayed in fullscreen.
- *
- * Returns null if there is currently no fullscreen element. You can use
- * this to determine if the page is in fullscreen mode.
- *
- * myVideo = new VideoElement();
- * if (document.fullscreenElement == null) {
- * myVideo.requestFullscreen();
- * print(document.fullscreenElement == myVideo); // true
- * }
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenElement')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- Element get fullscreenElement => _webkitFullscreenElement;
-
- /**
- * Returns true if this document can display elements in fullscreen mode.
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenEnabled')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get fullscreenEnabled => _webkitFullscreenEnabled;
-
- @DomName('Document.webkitHidden')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get hidden => _webkitHidden;
-
- @DomName('Document.visibilityState')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.FIREFOX)
- @SupportedBrowser(SupportedBrowser.IE, '10')
- @Experimental()
-$if DART2JS
- String get visibilityState => JS('String',
- '(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
- '#.webkitVisibilityState)', this, this, this, this);
-$else
- String get visibilityState => _webkitVisibilityState;
-$endif
$if DARTIUM
/**
diff --git a/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
index 4919649..e6ad32f 100644
--- a/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
@@ -28,7 +28,7 @@
ButtonInputElement {
factory InputElement({String type}) {
- var e = document.createElement("input");
+ InputElement e = document.createElement("input");
if (type != null) {
try {
// IE throws an exception for unknown types.
diff --git a/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate
index 25510dc..396ffcd 100644
--- a/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate
@@ -10,8 +10,7 @@
// Override default options, since IE returns SelectElement itself and it
// does not operate as a List.
List<OptionElement> get options {
- var options = this.querySelectorAll('option').where(
- (e) => e is OptionElement).toList();
+ var options = new List<OptionElement>.from(this.querySelectorAll('option'));
return new UnmodifiableListView(options);
}
diff --git a/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate b/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
index 6218e29..b82020f 100644
--- a/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
@@ -49,14 +49,14 @@
@DomName('IDBFactory.deleteDatabase')
Future<IdbFactory> deleteDatabase(String name,
- {void onBlocked(Event)}) {
+ {void onBlocked(Event e)}) {
try {
var request = _deleteDatabase(name);
if (onBlocked != null) {
request.onBlocked.listen(onBlocked);
}
- var completer = new Completer.sync();
+ var completer = new Completer<IdbFactory>.sync();
request.onSuccess.listen((e) {
completer.complete(this);
});
@@ -100,12 +100,13 @@
* Ties a request to a completer, so the completer is completed when it succeeds
* and errors out when the request errors.
*/
-Future _completeRequest(Request request) {
- var completer = new Completer.sync();
+Future/*<T>*/ _completeRequest/*<T>*/(Request request) {
+ var completer = new Completer/*<T>*/.sync();
// TODO: make sure that completer.complete is synchronous as transactions
// may be committed if the result is not processed immediately.
request.onSuccess.listen((e) {
- completer.complete(request.result);
+ var result = _cast/*<T>*/(request.result);
+ completer.complete(result);
});
request.onError.listen(completer.completeError);
return completer.future;
diff --git a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
index 1363056..4c74806 100644
--- a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
@@ -137,18 +137,18 @@
/**
* Helper for iterating over cursors in a request.
*/
- static Stream<Cursor> _cursorStreamFromResult(Request request,
+ static Stream/*<T>*/ _cursorStreamFromResult/*<T extends Cursor>*/(Request request,
bool autoAdvance) {
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController(sync: true);
+ var controller = new StreamController/*<T>*/(sync: true);
//TODO: Report stacktrace once issue 4061 is resolved.
request.onError.listen(controller.addError);
request.onSuccess.listen((e) {
- Cursor cursor = request.result;
+ var cursor = _cast/*<T>*/(request.result);
if (cursor == null) {
controller.close();
} else {
@@ -161,3 +161,6 @@
return controller.stream;
}
}
+
+// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
+/*=To*/ _cast/*<To>*/(dynamic x) => x;
diff --git a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
index 1b13a76..3018eb1 100644
--- a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
@@ -10,7 +10,7 @@
factory $CLASSNAME(String type,
{bool canBubble: false, bool cancelable: false, Object data,
String origin, String lastEventId,
- Window source, List messagePorts}) {
+ Window source, List<MessagePort> messagePorts}) {
if (source == null) {
source = window;
}
@@ -22,7 +22,7 @@
messagePorts);
}
$endif
- var event = document._createEvent("MessageEvent");
+ MessageEvent event = document._createEvent("MessageEvent");
event._initMessageEvent(type, canBubble, cancelable, data, origin,
lastEventId, source, messagePorts);
return event;
diff --git a/tools/dom/templates/html/impl/impl_MutationEvent.darttemplate b/tools/dom/templates/html/impl/impl_MutationEvent.darttemplate
deleted file mode 100644
index c4a30c6..0000000
--- a/tools/dom/templates/html/impl/impl_MutationEvent.darttemplate
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of $LIBRARYNAME;
-
-$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
- factory $CLASSNAME(String type,
- {bool canBubble: false, bool cancelable: false, Node relatedNode,
- String prevValue, String newValue, String attrName, int attrChange: 0}) {
-
- var event = document._createEvent('MutationEvent');
- event._initMutationEvent(type, canBubble, cancelable, relatedNode,
- prevValue, newValue, attrName, attrChange);
- return event;
- }
-$!MEMBERS
-}
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 4362733..27c8e49 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -213,7 +213,7 @@
set nodes(Iterable<Node> value) {
// Copy list first since we don't want liveness during iteration.
// TODO(jacobr): there is a better way to do this.
- List copy = new List.from(value);
+ var copy = value.toList();
text = '';
for (Node node in copy) {
append(node);
diff --git a/tools/dom/templates/html/impl/impl_Storage.darttemplate b/tools/dom/templates/html/impl/impl_Storage.darttemplate
index ff99d70..609355e 100644
--- a/tools/dom/templates/html/impl/impl_Storage.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Storage.darttemplate
@@ -37,11 +37,11 @@
}
// TODO(nweiz): update this when maps support lazy iteration
- bool containsValue(String value) => values.any((e) => e == value);
+ bool containsValue(Object value) => values.any((e) => e == value);
- bool containsKey(String key) => _getItem(key) != null;
+ bool containsKey(Object key) => _getItem(key) != null;
- String operator [](String key) => _getItem(key);
+ String operator [](Object key) => _getItem(key);
void operator []=(String key, String value) { _setItem(key, value); }
@@ -50,7 +50,7 @@
return this[key];
}
- String remove(String key) {
+ String remove(Object key) {
final value = this[key];
_removeItem(key);
return value;
@@ -68,13 +68,13 @@
}
Iterable<String> get keys {
- final keys = [];
+ final keys = <String>[];
forEach((k, v) => keys.add(k));
return keys;
}
Iterable<String> get values {
- final values = [];
+ final values = <String>[];
forEach((k, v) => values.add(v));
return values;
}
diff --git a/tools/dom/templates/html/impl/impl_StorageEvent.darttemplate b/tools/dom/templates/html/impl/impl_StorageEvent.darttemplate
index 9d546b3..551e2c7 100644
--- a/tools/dom/templates/html/impl/impl_StorageEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_StorageEvent.darttemplate
@@ -11,7 +11,7 @@
{bool canBubble: false, bool cancelable: false, String key, String oldValue,
String newValue, String url, Storage storageArea}) {
- var e = document._createEvent("StorageEvent");
+ StorageEvent e = document._createEvent("StorageEvent");
e._initStorageEvent(type, canBubble, cancelable, key, oldValue,
newValue, url, storageArea);
return e;
diff --git a/tools/dom/templates/html/impl/impl_TextEvent.darttemplate b/tools/dom/templates/html/impl/impl_TextEvent.darttemplate
index e12cc8b..148c718 100644
--- a/tools/dom/templates/html/impl/impl_TextEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_TextEvent.darttemplate
@@ -12,7 +12,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("TextEvent");
+ TextEvent e = document._createEvent("TextEvent");
e._initTextEvent(type, canBubble, cancelable, view, data);
return e;
}
diff --git a/tools/dom/templates/html/impl/impl_TouchEvent.darttemplate b/tools/dom/templates/html/impl/impl_TouchEvent.darttemplate
index 3ee2462..3fa5e27 100644
--- a/tools/dom/templates/html/impl/impl_TouchEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_TouchEvent.darttemplate
@@ -15,7 +15,7 @@
if (view == null) {
view = window;
}
- var e = document._createEvent("TouchEvent");
+ TouchEvent e = document._createEvent("TouchEvent");
e._initTouchEvent(touches, targetTouches, changedTouches, type, view,
screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey);
return e;
diff --git a/tools/dom/templates/html/impl/impl_UIEvent.darttemplate b/tools/dom/templates/html/impl/impl_UIEvent.darttemplate
index 5894720..405d06d 100644
--- a/tools/dom/templates/html/impl/impl_UIEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_UIEvent.darttemplate
@@ -19,7 +19,7 @@
if (view == null) {
view = window;
}
- final e = document._createEvent("UIEvent");
+ UIEvent e = document._createEvent("UIEvent");
e._initUIEvent(type, canBubble, cancelable, view, detail);
return e;
}
diff --git a/tools/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate
index 521fd00..c9f8279 100644
--- a/tools/dom/templates/html/impl/impl_Window.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -115,7 +115,7 @@
@DomName('Window.requestAnimationFrame')
int requestAnimationFrame(FrameRequestCallback callback) {
_ensureRequestAnimationFrame();
- return _requestAnimationFrame(_wrapZone(callback));
+ return _requestAnimationFrame(_wrapZone/*<num, dynamic>*/(callback));
}
/**
@@ -341,12 +341,11 @@
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
var stream = new _EventStream(e, _eventType, useCapture);
$if DART2JS
- var controller = new StreamController(sync: true);
+ var controller = new StreamController<BeforeUnloadEvent>(sync: true);
stream.listen((event) {
var wrapped = new _BeforeUnloadEvent(event);
controller.add(wrapped);
- return wrapped.returnValue;
});
return controller.stream;
diff --git a/tools/gyp/configurations.gypi b/tools/gyp/configurations.gypi
index 6a4b796..e5ab11a 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -26,6 +26,8 @@
['"<(target_arch)"=="simarm64"', { 'dart_target_arch': 'SIMARM64', }],
['"<(target_arch)"=="mips"', { 'dart_target_arch': 'MIPS', }],
['"<(target_arch)"=="simmips"', { 'dart_target_arch': 'SIMMIPS', }],
+ ['"<(target_arch)"=="simdbc"', { 'dart_target_arch': 'SIMDBC', }],
+ ['"<(target_arch)"=="simdbc64"', { 'dart_target_arch': 'SIMDBC64', }],
[ 'OS=="linux"', { 'dart_target_os': 'Linux', } ],
[ 'OS=="mac"', { 'dart_target_os': 'Macos', } ],
[ 'OS=="win"', { 'dart_target_os': 'Win', } ],
@@ -132,6 +134,14 @@
],
},
+ 'Dart_simdbc_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'TARGET_ARCH_DBC',
+ 'USING_SIMULATOR',
+ ]
+ },
+
'Dart_Debug': {
'abstract': 1,
},
@@ -356,6 +366,47 @@
],
},
+ 'DebugSIMDBC': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Debug',
+ 'Dart_<(dart_target_os)_Base',
+ 'Dart_<(dart_target_os)_simdbc_Base',
+ 'Dart_<(dart_target_os)_Debug',
+ ],
+ 'defines': [
+ 'DEBUG',
+ ],
+ },
+
+ 'ReleaseSIMDBC': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Release',
+ 'Dart_<(dart_target_os)_Base',
+ 'Dart_<(dart_target_os)_simdbc_Base',
+ 'Dart_<(dart_target_os)_Release',
+ ],
+ },
+
+ 'DebugSIMDBC64': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Debug',
+ 'Dart_<(dart_target_os)_Base',
+ 'Dart_<(dart_target_os)_simdbc64_Base',
+ 'Dart_<(dart_target_os)_Debug',
+ ],
+ 'defines': [
+ 'DEBUG',
+ ],
+ },
+
+ 'ReleaseSIMDBC64': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Release',
+ 'Dart_<(dart_target_os)_Base',
+ 'Dart_<(dart_target_os)_simdbc64_Base',
+ 'Dart_<(dart_target_os)_Release',
+ ],
+ },
# ARM and MIPS hardware configurations are only for Linux and Android.
'DebugXARM': {
@@ -741,6 +792,52 @@
],
},
+ 'DebugAndroidSIMDBC': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Debug',
+ 'Dart_Android_Base',
+ # Default SIMDBC on Android targets arm.
+ 'Dart_Android_arm_Base',
+ 'Dart_Android_Debug',
+ ],
+ 'defines': [
+ 'DEBUG',
+ ],
+ },
+
+ 'ReleaseAndroidSIMDBC': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Release',
+ 'Dart_Android_Base',
+ # Default SIMDBC on Android targets arm.
+ 'Dart_Android_arm_Base',
+ 'Dart_Android_Release',
+ ],
+ },
+
+ 'DebugAndroidSIMDBC64': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Debug',
+ 'Dart_Android_Base',
+ # Default SIMDBC on Android targets arm64.
+ 'Dart_Android_arm64_Base',
+ 'Dart_Android_Debug',
+ ],
+ 'defines': [
+ 'DEBUG',
+ ],
+ },
+
+ 'ReleaseAndroidSIMDBC64': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_simdbc_Base', 'Dart_Release',
+ 'Dart_Android_Base',
+ # Default SIMDBC on Android targets arm64.
+ 'Dart_Android_arm64_Base',
+ 'Dart_Android_Release',
+ ],
+ },
+
# These targets assume that target_arch is passed in explicitly
# by the containing project (e.g., chromium).
'Debug': {
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index 98d28fa..05292bf 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -113,6 +113,18 @@
],
},
+ 'Dart_Linux_simdbc_Base': {
+ 'abstract': 1,
+ 'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
+ 'ldflags': [ '-m32', ],
+ },
+
+ 'Dart_Linux_simdbc64_Base': {
+ 'abstract': 1,
+ 'cflags': [ '-O3', '-m64', '-msse2', '-mfpmath=sse' ],
+ 'ldflags': [ '-m64', ],
+ },
+
# ARM cross-build
'Dart_Linux_xarm_Base': {
'abstract': 1,
diff --git a/tools/gyp/configurations_msvs.gypi b/tools/gyp/configurations_msvs.gypi
index 3650127..adcc1d4 100644
--- a/tools/gyp/configurations_msvs.gypi
+++ b/tools/gyp/configurations_msvs.gypi
@@ -36,6 +36,12 @@
'Dart_Win_simmips_Base': {
'abstract': 1,
},
+ 'Dart_Win_simdbc_Base': {
+ 'abstract': 1,
+ },
+ 'Dart_Win_simdbc64_Base': {
+ 'abstract': 1,
+ },
'Dart_Win_Debug': {
'abstract': 1,
'msvs_settings': {
diff --git a/tools/gyp/configurations_xcode.gypi b/tools/gyp/configurations_xcode.gypi
index 367f8f2..e9a68f6 100644
--- a/tools/gyp/configurations_xcode.gypi
+++ b/tools/gyp/configurations_xcode.gypi
@@ -77,6 +77,12 @@
'Dart_Macos_simmips_Base': {
'abstract': 1,
},
+ 'Dart_Macos_simdbc_Base': {
+ 'abstract': 1,
+ },
+ 'Dart_Macos_simdbc64_Base': {
+ 'abstract': 1,
+ },
'Dart_Macos_Debug': {
'abstract': 1,
'xcode_settings': {
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 147cd99..161252a 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -52,6 +52,7 @@
bool useSdk = configuration['use_sdk'];
bool isCsp = configuration['csp'];
bool useCps = configuration['cps_ir'];
+ bool useBlobs = configuration['use_blobs'];
switch (compiler) {
case 'dart2analyzer':
@@ -77,7 +78,8 @@
return new PrecompilerCompilerConfiguration(
isDebug: isDebug,
isChecked: isChecked,
- arch: configuration['arch']);
+ arch: configuration['arch'],
+ useBlobs: useBlobs);
case 'none':
return new NoneCompilerConfiguration(
isDebug: isDebug,
@@ -299,10 +301,12 @@
class PrecompilerCompilerConfiguration extends CompilerConfiguration {
final String arch;
+ final bool useBlobs;
- PrecompilerCompilerConfiguration({bool isDebug, bool isChecked, String arch})
+ PrecompilerCompilerConfiguration({bool isDebug, bool isChecked, String arch, bool useBlobs})
: super._subclass(isDebug: isDebug, isChecked: isChecked),
- arch = arch;
+ arch = arch,
+ useBlobs = useBlobs;
int computeTimeoutMultiplier() {
int multiplier = 2;
@@ -317,14 +321,16 @@
CommandBuilder commandBuilder,
List arguments,
Map<String, String> environmentOverrides) {
- return new CommandArtifact(<Command>[
- this.computeCompilationCommand(tempDir, buildDir, CommandBuilder.instance,
- arguments, environmentOverrides),
- this.computeAssembleCommand(tempDir, buildDir, CommandBuilder.instance,
- arguments, environmentOverrides),
- this.computeRemoveAssemblyCommand(tempDir, buildDir,
- CommandBuilder.instance, arguments, environmentOverrides)
- ], '$tempDir', 'application/dart-precompiled');
+ var commands = new List<Command>();
+ commands.add(this.computeCompilationCommand(tempDir, buildDir, CommandBuilder.instance,
+ arguments, environmentOverrides));
+ if (!useBlobs) {
+ commands.add(this.computeAssembleCommand(tempDir, buildDir, CommandBuilder.instance,
+ arguments, environmentOverrides));
+ commands.add(this.computeRemoveAssemblyCommand(tempDir, buildDir,
+ CommandBuilder.instance, arguments, environmentOverrides));
+ }
+ return new CommandArtifact(commands, '$tempDir', 'application/dart-precompiled');
}
CompilationCommand computeCompilationCommand(
@@ -336,6 +342,9 @@
var exec = "$buildDir/dart_bootstrap";
var args = new List();
args.add("--gen-precompiled-snapshot=$tempDir");
+ if (useBlobs) {
+ args.add("--use_blobs");
+ }
args.addAll(arguments);
return commandBuilder.getCompilationCommand('precompiler', tempDir, !useSdk,
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 8766322..7191342 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -19,6 +19,8 @@
// [RuntimeConfiguration] in [configuration] there.
factory RuntimeConfiguration(Map configuration) {
String runtime = configuration['runtime'];
+ bool useBlobs = configuration['use_blobs'];
+
switch (runtime) {
case 'ContentShellOnAndroid':
case 'DartiumOnAndroid':
@@ -52,7 +54,7 @@
return new DartProductRuntimeConfiguration();
case 'dart_precompiled':
- return new DartPrecompiledRuntimeConfiguration();
+ return new DartPrecompiledRuntimeConfiguration(useBlobs: useBlobs);
case 'drt':
return new DrtRuntimeConfiguration();
@@ -171,6 +173,8 @@
case 'simmips':
case 'mips':
case 'simarm64':
+ case 'simdbc':
+ case 'simdbc64':
multiplier *= 4;
break;
}
@@ -235,13 +239,16 @@
augmentedArgs.addAll(arguments);
return <Command>[
- commandBuilder.getVmCommand(suite.dartVmProductBinaryFileName,
+ commandBuilder.getVmCommand(suite.dartVmBinaryFileName,
augmentedArgs, environmentOverrides)
];
}
}
class DartPrecompiledRuntimeConfiguration extends DartVmRuntimeConfiguration {
+ final bool useBlobs;
+ DartPrecompiledRuntimeConfiguration({bool useBlobs}) : useBlobs = useBlobs;
+
List<Command> computeRuntimeCommands(
TestSuite suite,
CommandBuilder commandBuilder,
@@ -256,6 +263,9 @@
var augmentedArgs = new List();
augmentedArgs.add("--run-precompiled-snapshot=${artifact.filename}");
+ if (useBlobs) {
+ augmentedArgs.add("--use_blobs");
+ }
augmentedArgs.addAll(arguments);
return <Command>[
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 9cbd3c2..d4849a4 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -148,7 +148,9 @@
'simarmv6',
'simarmv5te',
'simarm64',
- 'simmips'
+ 'simmips',
+ 'simdbc',
+ 'simdbc64',
],
'x64'),
new _TestOptionSpecification(
@@ -184,6 +186,9 @@
'noopt', 'Run an in-place precompilation', ['--noopt'], [], false,
type: 'bool'),
new _TestOptionSpecification(
+ 'use_blobs', 'Use mmap instead of shared libraries for precompilation', ['--use-blobs'], [], false,
+ type: 'bool'),
+ new _TestOptionSpecification(
'timeout', 'Timeout in seconds', ['-t', '--timeout'], [], -1,
type: 'int'),
new _TestOptionSpecification(
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index d288da8..dbab65e 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -234,21 +234,6 @@
return dartExecutable;
}
- String get dartVmProductBinaryFileName {
- // Controlled by user with the option "--dart".
- String dartExecutable = configuration['dart'];
-
- if (dartExecutable == '') {
- String suffix = executableBinarySuffix;
- dartExecutable = useSdk
- ? '$buildDir/dart-sdk/bin/dart_product$suffix'
- : '$buildDir/dart_product$suffix';
- }
-
- TestUtils.ensureExists(dartExecutable, configuration);
- return dartExecutable;
- }
-
String get d8FileName {
var suffix = getExecutableSuffix('d8');
var d8Dir = TestUtils.dartDir.append('third_party/d8');
diff --git a/tools/utils.py b/tools/utils.py
index 6965a1c..02fe8ef 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -240,6 +240,8 @@
'simarmv5te': 'ia32',
'simmips': 'ia32',
'simarm64': 'ia32',
+ 'simdbc': 'ia32',
+ 'simdbc64': 'ia32',
}
ARCH_GUESS = GuessArchitecture()