Version 1.12.0-dev.5.0
Merge commit '2ca0bc6d5a844c7e107e5502ec37669eabb35841' into dev
diff --git a/.gitattributes b/.gitattributes
index d77d09b..9dfc906 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -16,6 +16,9 @@
tests/compiler/dart2js_extra/literal_string_juxtaposition_test.dart -text
tests/language/raw_string_test.dart -text
tests/language/multiline_strings_test.dart -text
+tests/language/multiline_newline_cr.dart -text
+tests/language/multiline_newline_crlf.dart -text
+tests/language/multiline_newline_lf.dart -text
tests/lib/convert/json_pretty_test.dart -text
tests/lib/mirrors/method_mirror_source_line_ending_test.dart -text
tests/lib/mirrors/method_mirror_source_line_ending_cr.dart -text
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8383615..feb8c48 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -68,6 +68,9 @@
* A crashing bug involving transformers that only apply to non-public code
has been fixed.
+ * A deadlock caused by declaring transformer followed by a lazy transformer
+ (such as the built-in `$dart2js` transformer) has been fixed.
+
* A stack overflow caused by a transformer being run multiple times on the
package that defines it has been fixed.
@@ -76,6 +79,29 @@
[package spec proposal]: https://github.com/lrhn/dep-pkgspec
+* Formatter (`dartfmt`)
+
+ * Over 50 bugs fixed.
+
+ * Optimized line splitter is much faster and produces better output on
+ complex code.
+
+### VM Service Protocol Changes
+
+* **BREAKING** The service protocol now sends JSON-RPC 2.0-compatible
+ server-to-client events. To reflect this, the service protocol version is
+ now 2.0.
+
+* The service protocol now includes a `"jsonrpc"` property in its responses, as
+ opposed to `"json-rpc"`.
+
+* The service protocol now properly handles requests with non-string ids.
+ Numeric ids are no longer converted to strings, and null ids now don't produce
+ a response.
+
+* Some RPCs that didn't include a `"jsonrpc"` property in their responses now
+ include one.
+
## 1.11.2
### Core library changes
diff --git a/DEPS b/DEPS
index 50369e4..e6693ff 100644
--- a/DEPS
+++ b/DEPS
@@ -31,17 +31,17 @@
"github_mirror":
"https://chromium.googlesource.com/external/github.com/dart-lang/%s.git",
- "gyp_rev": "@1752",
+ "gyp_rev": "@6ee91ad8659871916f9aa840d42e1513befdf638",
"co19_rev": "@f95f109fea67127a220958794ef5200a63cb454c",
"chromium_url": "http://src.chromium.org/svn",
"chromium_git": "https://chromium.googlesource.com",
# Revisions of /third_party/* dependencies.
"7zip_rev" : "@19997",
- "analyzer_cli_rev" : "@7436b45b160f99e806bef2aafd1e971e1aedfc4d",
+ "analyzer_cli_rev" : "@c4e628a8467f75ded563f029dfb2f1738856f471",
"args_tag": "@0.13.0",
"async_tag": "@1.2.0",
- "barback_tag" : "@0.15.2+5",
+ "barback_tag" : "@0.15.2+6",
"charcode_tag": "@1.1.0",
"chrome_rev" : "@19997",
"clang_rev" : "@28450",
@@ -51,8 +51,8 @@
"csslib_tag" : "@0.12.0",
"dartdoc_tag" : "@v0.1.0+5",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
- "dart_style_tag": "@0.1.8+1",
- "dev_compiler_rev": "@0.1.1",
+ "dart_style_tag": "@0.2.0",
+ "dev_compiler_rev": "@0.1.3",
"fake_async_rev" : "@38614",
"firefox_jsshell_rev" : "@45554",
"glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
@@ -65,7 +65,7 @@
"idl_parser_rev": "@6316d5982dc24b34d09dd8b10fbeaaff28d83a48",
"intl_rev": "@32047558bd220a53c1f4d93a26d54b83533b1475",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
- "json_rpc_2_rev": "@a38eefd116d910199de205f962af92fed87c164c",
+ "json_rpc_2_tag": "@1.1.1",
"linter_tag": "@0.1.0",
"logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
"markdown_rev": "@56b0fd6c018d6103862d07e8e27407b9ea3b963d",
@@ -100,7 +100,7 @@
"stack_trace_tag": "@1.3.4",
"string_scanner_rev": "@3e7617d6f74ba382e9b6130b1cc12091d89a9bc5",
"sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
- "test_tag": "@0.12.3+4",
+ "test_tag": "@0.12.3+8",
"test_reflective_loader_tag": "@0.0.3",
"utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
"unittest_tag": "@0.11.6",
@@ -122,7 +122,7 @@
deps = {
# Stuff needed for GYP to run.
Var("dart_root") + "/third_party/gyp":
- (Var("googlecode_url") % "gyp") + "/trunk" + Var("gyp_rev"),
+ Var('chromium_git') + '/external/gyp.git' + Var("gyp_rev"),
Var("dart_root") + "/tests/co19/src":
(Var("github_mirror") % "co19") + Var("co19_rev"),
@@ -195,7 +195,7 @@
(Var("github_mirror") % "csslib") + Var("csslib_tag"),
Var("dart_root") + "/third_party/pkg_tested/dart_style":
(Var("github_mirror") % "dart_style") + Var("dart_style_tag"),
- Var("dart_root") + "/third_party/pkg/dartdoc":
+ Var("dart_root") + "/third_party/pkg/dartdoc":
"https://github.com/dart-lang/dartdoc.git" + Var("dartdoc_tag"),
Var("dart_root") + "/third_party/pkg/dev_compiler":
"https://github.com/dart-lang/dev_compiler.git" + Var("dev_compiler_rev"),
@@ -216,7 +216,7 @@
Var("dart_root") + "/third_party/pkg/intl":
(Var("github_mirror") % "intl") + Var("intl_rev"),
Var("dart_root") + "/third_party/pkg/json_rpc_2":
- (Var("github_mirror") % "json_rpc_2") + Var("json_rpc_2_rev"),
+ (Var("github_mirror") % "json_rpc_2") + Var("json_rpc_2_tag"),
Var("dart_root") + "/third_party/pkg/linter":
(Var("github_mirror") % "linter") + Var("linter_tag"),
Var("dart_root") + "/third_party/pkg/logging":
@@ -230,16 +230,16 @@
(Var("github_mirror") % "metatest") + Var("metatest_rev"),
Var("dart_root") + "/third_party/pkg/mime":
(Var("github_mirror") % "mime") + Var("mime_rev"),
- Var("dart_root") + "/third_party/pkg/mustache4dart":
- Var("chromium_git")
- + "/external/github.com/valotas/mustache4dart.git"
+ Var("dart_root") + "/third_party/pkg/mustache4dart":
+ Var("chromium_git")
+ + "/external/github.com/valotas/mustache4dart.git"
+ Var("mustache4dart_rev"),
Var("dart_root") + "/third_party/pkg/oauth2":
(Var("github_mirror") % "oauth2") + Var("oauth2_rev"),
Var("dart_root") + "/third_party/pkg/observe":
(Var("github_mirror") % "observe") + Var("observe_rev"),
Var("dart_root") + "/third_party/observatory_pub_packages":
- (Var("github_mirror") % "observatory_pub_packages")
+ (Var("github_mirror") % "observatory_pub_packages")
+ Var("observatory_pub_packages_rev"),
Var("dart_root") + "/third_party/pkg/package_config":
(Var("github_mirror") % "package_config") +
@@ -254,11 +254,11 @@
(Var("github_mirror") % "pub_semver") + Var("pub_semver_tag"),
Var("dart_root") + "/third_party/pkg/pub":
(Var("github_mirror") % "pub") + Var("pub_rev"),
- Var("dart_root") + "/third_party/pkg/pub_cache":
+ Var("dart_root") + "/third_party/pkg/pub_cache":
(Var("github_mirror") % "pub_cache") + Var("pub_cache_tag"),
- Var("dart_root") + "/third_party/pkg/quiver":
- Var("chromium_git")
- + "/external/github.com/google/quiver-dart.git"
+ Var("dart_root") + "/third_party/pkg/quiver":
+ Var("chromium_git")
+ + "/external/github.com/google/quiver-dart.git"
+ Var("quiver_tag"),
Var("dart_root") + "/third_party/pkg/scheduled_test":
(Var("github_mirror") % "scheduled_test") +
@@ -266,7 +266,7 @@
Var("dart_root") + "/third_party/pkg/shelf":
(Var("github_mirror") % "shelf") + Var("shelf_rev"),
Var("dart_root") + "/third_party/pkg/shelf_static":
- "https://github.com/kevmoo/shelf_static.dart.git" +
+ "https://github.com/dart-lang/shelf_static.git" +
Var("shelf_static_rev"),
Var("dart_root") + "/third_party/pkg/shelf_web_socket":
(Var("github_mirror") % "shelf_web_socket") +
diff --git a/pkg/analysis_server/benchmark/integration/README.md b/pkg/analysis_server/benchmark/integration/README.md
new file mode 100644
index 0000000..78431f9
--- /dev/null
+++ b/pkg/analysis_server/benchmark/integration/README.md
@@ -0,0 +1,72 @@
+# Running Benchmarks
+
+There are two entry points for running benchmarks:
+* **main.dart** - a general Dart application for running performance benchmarks
+* **local_runner.dart** - an example Dart application
+which sets up the local environment
+and then calls main.dart to run performance benchmarks
+
+## local_runner.dart
+
+This Dart application is one example for running performance benchmarks.
+When run, this application 1) extracts a branch from a git repository
+into a temporary directory, and 2) creates a symlink to the out or xcodebuild
+directory for proper package-root package resolution.
+Once setup is complete, this applications calls main.dart
+
+The required command line arguments are
+* **gitDir** = a path to the git repository containing the initial target source
+* **branch** = the branch containing the initial target source
+* **inputFile** = the instrumentation or log file
+
+Additional arguments are passed directly to main.dart.
+For example, you may want to specify --newTaskModel to measure performance
+with the new task model versus the old task model,
+or if the log was recorded on one machine and is played back on another,
+then you might need to specify -m<oldSrcPath>,<newSrcPath>
+to map the source paths for playback.
+When specifying additional arguments, any occurrences of @tmpSrcDir@
+will be replaced with the absolute path of the temporary directory
+into which the source was extracted.
+
+## main.dart
+
+This Dart application reads an instrumentation or local log file produced by
+analysis server, "replays" that interaction with the analysis server,
+compares the notifications and responses with what was recorded in the log,
+and produces a report. It assumes that the environment for playback has
+already been setup.
+The required command line arguments are
+* **-i, --input <filePath>**
+The input file specifying how this client should interact with the server.
+If the input file name is "stdin", then the instructions are read from stdin.
+* **-m, --map <oldSrcPath>,<newSrcPath>**
+This option defines a mapping from the original source directory <oldSrcPath>
+when the instrumentation or log file was generated
+to the target source directory <newSrcPath> used during performance testing.
+Multiple mappings can be specified.
+WARNING: The contents of the target directory will be modified
+* **-t, --tmpSrcDir <dirPath>**
+The temporary directory containing source used during performance measurement.
+WARNING: The contents of the target directory will be modified
+* **--newTaskModel** enable the use of the new task model
+* **-d, --diagnosticPort** localhost port on which server
+ will provide diagnostic web pages
+* **-v, --verbose** Verbose logging
+* **--vv** Extra verbose logging
+* **-h, --help** Print this help information
+
+For each request recorded in the input file,
+the application sends a corresponding request to the analysis server
+and waits up to 60 seconds for a response to that request.
+If a response in not received in that time, then the application exits.
+Any responses that are received are compared with the recorded response.
+
+For each analysis-complete notification recorded in the input file,
+the application waits for the corresponding analysis-complete notification
+from the running analysis server.
+While it is waiting for an analysis-complete notification,
+the application monitors the stream of notifications.
+If there is a period of more than 60 seconds during which no communication
+is received from the server, the application assumes that the server is hung
+and exits.
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index 19243ea..a3167810 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:math' show max, sqrt;
-import 'package:analyzer/src/generated/engine.dart' as engine;
import 'package:logging/logging.dart';
import '../../test/integration/integration_test_methods.dart';
@@ -44,7 +43,14 @@
*/
static const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 5);
- final Logger logger;
+ final Logger logger = new Logger('Driver');
+
+ final bool newTaskModel;
+
+ /**
+ * The diagnostic port for Analysis Server or `null` if none.
+ */
+ final int diagnosticPort;
/**
* A flag indicating whether the server is running.
@@ -64,7 +70,7 @@
*/
Completer<Results> _runCompleter = new Completer<Results>();
- Driver(this.logger);
+ Driver({this.newTaskModel, this.diagnosticPort});
/**
* Return a [Future] that completes with the [Results] of running
@@ -97,7 +103,7 @@
* Launch the analysis server.
* Return a [Future] that completes when analysis server has started.
*/
- Future startServer({int diagnosticPort}) async {
+ Future startServer() async {
logger.log(Level.FINE, 'starting server');
initializeInttestMixin();
server = new Server();
@@ -108,7 +114,9 @@
});
running = true;
return server
- .start(diagnosticPort: diagnosticPort /*profileServer: true*/)
+ .start(
+ diagnosticPort: diagnosticPort,
+ newTaskModel: newTaskModel /*profileServer: true*/)
.then((params) {
server.listenToOutput(dispatchNotification);
server.exitCode.then((_) {
@@ -193,7 +201,7 @@
_printDuration(sb, new Duration(microseconds: meanTime));
_printDuration(sb, time90th);
_printDuration(sb, time99th);
- _printColumn(sb, standardDeviation.toString(), 15, rightJustified: true);
+ _printDuration(sb, new Duration(microseconds: standardDeviation));
_printDuration(sb, minTime);
_printDuration(sb, maxTime);
_printDuration(sb, new Duration(microseconds: totalTimeMicros));
@@ -212,9 +220,8 @@
}
void _printDuration(StringBuffer sb, Duration duration) {
- sb.write(' ');
- sb.write(duration);
- sb.write(',');
+ _printColumn(sb, duration.inMilliseconds.toString(), 15,
+ rightJustified: true);
}
}
@@ -231,11 +238,6 @@
void printResults() {
print('');
print('==================================================================');
- if (engine.AnalysisEngine.instance.useTaskModel) {
- print('New task model');
- } else {
- print('Old task model');
- }
print('');
List<String> keys = measurements.keys.toList()..sort();
int keyLen = keys.fold(0, (int len, String key) => max(len, key.length));
@@ -263,11 +265,11 @@
}
}
/// TODO(danrubel) *** print warnings if driver caches are not empty ****
- print('');
- print(
- '(1) uxr = UneXpected Results, or responses received from the server');
- print(
- ' that do not match the recorded response for that request.');
+ print('''
+
+(1) uxr = UneXpected Results or responses received from the server
+ that do not match the recorded response for that request.
+(2) all times in milliseconds''');
}
/**
@@ -294,7 +296,7 @@
_printColumn(sb, 'error', 6, rightJustified: true);
_printColumn(sb, 'uxr(1)', 6, rightJustified: true);
sb.write(' ');
- _printColumn(sb, 'mean', 15);
+ _printColumn(sb, 'mean(2)', 15);
_printColumn(sb, '90th', 15);
_printColumn(sb, '99th', 15);
_printColumn(sb, 'std-dev', 15);
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index ef90131..3d9fd5a 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -62,7 +62,7 @@
* from location where instrumentation or log file was generated
* to the target location of the source using during performance measurement.
*/
- final Map<String, String> srcPathMap;
+ final PathMap srcPathMap;
/**
* The root directory for all source being modified
@@ -70,13 +70,7 @@
*/
final String tmpSrcDirPath;
- /**
- * The diagnostic port for Analysis Server or `null` if none.
- */
- final int diagnosticPort;
-
- CommonInputConverter(this.tmpSrcDirPath, this.srcPathMap,
- {this.diagnosticPort});
+ CommonInputConverter(this.tmpSrcDirPath, this.srcPathMap);
/**
* Return an operation for the notification or `null` if none.
@@ -95,7 +89,7 @@
}
if (event == SERVER_CONNECTED) {
// {"event":"server.connected","params":{"version":"1.7.0"}}
- return new StartServerOperation(diagnosticPort: diagnosticPort);
+ return new StartServerOperation();
}
if (eventsSeen.add(event)) {
logger.log(Level.INFO, 'Ignored notification: $event\n $json');
@@ -182,6 +176,14 @@
this, requestMap.remove(json['id']), translateSrcPaths(json));
}
+ void logOverlayContent() {
+ logger.log(Level.WARNING, '${overlays.length} overlays');
+ List<String> allPaths = overlays.keys.toList()..sort();
+ for (String filePath in allPaths) {
+ logger.log(Level.WARNING, 'overlay $filePath\n${overlays[filePath]}');
+ }
+ }
+
/**
* Process an error response from the server by either
* completing the associated completer in the [responseCompleters]
@@ -242,13 +244,7 @@
*/
translateSrcPaths(json) {
if (json is String) {
- String result = json;
- srcPathMap.forEach((String oldPrefix, String newPrefix) {
- if (json.startsWith(oldPrefix)) {
- result = '$newPrefix${json.substring(oldPrefix.length)}';
- }
- });
- return result;
+ return srcPathMap.translate(json);
}
if (json is List) {
List result = [];
@@ -281,7 +277,7 @@
* from location where instrumentation or log file was generated
* to the target location of the source using during performance measurement.
*/
- final Map<String, String> srcPathMap;
+ final PathMap srcPathMap;
/**
* The root directory for all source being modified
@@ -290,11 +286,6 @@
final String tmpSrcDirPath;
/**
- * The diagnostic port for Analysis Server or `null` if none.
- */
- final int diagnosticPort;
-
- /**
* The number of lines read before the underlying converter was determined
* or the end of file was reached.
*/
@@ -312,7 +303,7 @@
*/
bool active = true;
- InputConverter(this.tmpSrcDirPath, this.srcPathMap, {this.diagnosticPort});
+ InputConverter(this.tmpSrcDirPath, this.srcPathMap);
@override
Operation convert(String line) {
@@ -331,11 +322,9 @@
throw 'Failed to determine input file format';
}
if (InstrumentationInputConverter.isFormat(line)) {
- converter = new InstrumentationInputConverter(tmpSrcDirPath, srcPathMap,
- diagnosticPort: diagnosticPort);
+ converter = new InstrumentationInputConverter(tmpSrcDirPath, srcPathMap);
} else if (LogFileInputConverter.isFormat(line)) {
- converter = new LogFileInputConverter(tmpSrcDirPath, srcPathMap,
- diagnosticPort: diagnosticPort);
+ converter = new LogFileInputConverter(tmpSrcDirPath, srcPathMap);
}
if (converter != null) {
return converter.convert(line);
@@ -350,6 +339,43 @@
}
}
+/**
+ * A container of [PathMapEntry]s used to translate a source path in the log
+ * before it is sent to the analysis server.
+ */
+class PathMap {
+ final List<PathMapEntry> entries = [];
+
+ void add(String oldSrcPrefix, String newSrcPrefix) {
+ entries.add(new PathMapEntry(oldSrcPrefix, newSrcPrefix));
+ }
+
+ String translate(String original) {
+ String result = original;
+ for (PathMapEntry entry in entries) {
+ result = entry.translate(result);
+ }
+ return result;
+ }
+}
+
+/**
+ * An entry in [PathMap] used to translate a source path in the log
+ * before it is sent to the analysis server.
+ */
+class PathMapEntry {
+ final String oldSrcPrefix;
+ final String newSrcPrefix;
+
+ PathMapEntry(this.oldSrcPrefix, this.newSrcPrefix);
+
+ String translate(String original) {
+ return original.startsWith(oldSrcPrefix)
+ ? '$newSrcPrefix${original.substring(oldSrcPrefix.length)}'
+ : original;
+ }
+}
+
class _InputSink extends ChunkedConversionSink<String> {
final Converter<String, Operation> converter;
final outSink;
diff --git a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
index 11e2f9a..790da05 100644
--- a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
@@ -30,9 +30,8 @@
StringBuffer readBuffer = null;
InstrumentationInputConverter(
- String tmpSrcDirPath, Map<String, String> srcPathMap,
- {int diagnosticPort})
- : super(tmpSrcDirPath, srcPathMap, diagnosticPort: diagnosticPort);
+ String tmpSrcDirPath, PathMap srcPathMap)
+ : super(tmpSrcDirPath, srcPathMap);
@override
Operation convert(String line) {
diff --git a/pkg/analysis_server/benchmark/integration/local_runner.dart b/pkg/analysis_server/benchmark/integration/local_runner.dart
index 1d8d245..78d8c2a 100644
--- a/pkg/analysis_server/benchmark/integration/local_runner.dart
+++ b/pkg/analysis_server/benchmark/integration/local_runner.dart
@@ -12,7 +12,7 @@
/*
* Parse arguments
*/
- if (args.length != 3) printHelp('Expected 3 arguments');
+ if (args.length < 3) printHelp('Expected 3 arguments');
var gitDir = new Directory(args[0]);
if (!gitDir.existsSync()) printHelp('${gitDir.path} does not exist');
if (!new Directory(join(gitDir.path, '.git')).existsSync()) printHelp(
@@ -58,15 +58,17 @@
]);
if (result.exitCode != 0) throw 'failed to link out or xcodebuild: $result';
/*
+ * Collect arguments
+ */
+ var perfArgs = ['-i${inputFile.path}', '-t$tmpSrcDirPath',];
+ for (int index = 3; index < args.length; ++index) {
+ perfArgs.add(args[index].replaceAll('@tmpSrcDir@', tmpSrcDirPath));
+ }
+ perfArgs.add('-m${gitDir.path},$tmpSrcDirPath');
+ /*
* Launch the performance analysis tool
*/
- performance.main([
- //'-vv', // very verbose
- //'-d8081', // analysis server localhost diagnostic port
- '-i${inputFile.path}',
- '-t$tmpSrcDirPath',
- '-m${gitDir.path},$tmpSrcDirPath',
- ]);
+ performance.main(perfArgs);
}
/// Print help and exit
@@ -76,9 +78,12 @@
print('Error: $errMsg');
print('');
}
- print('Arguments: <gitDir> <branch> <inputFile>');
- print('gitDir = git repository containing the initial target source');
- print('branch = the branch containing the initial target source');
- print('inputFile = the instrumentation or log file');
+ print('''Required arguments: <gitDir> <branch> <inputFile>
+gitDir = a path to the git repository containing the initial target source
+branch = the branch containing the initial target source
+inputFile = the instrumentation or log file
+
+Optional arguments:''');
+ print(performance.argParser.usage);
exit(1);
}
diff --git a/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
index dd6c35c..0781bae 100644
--- a/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
@@ -23,9 +23,8 @@
* into a series of operations to be sent to the analysis server.
*/
class LogFileInputConverter extends CommonInputConverter {
- LogFileInputConverter(String tmpSrcDirPath, Map<String, String> srcPathMap,
- {int diagnosticPort})
- : super(tmpSrcDirPath, srcPathMap, diagnosticPort: diagnosticPort);
+ LogFileInputConverter(String tmpSrcDirPath, PathMap srcPathMap)
+ : super(tmpSrcDirPath, srcPathMap);
@override
Operation convert(String line) {
diff --git a/pkg/analysis_server/benchmark/integration/main.dart b/pkg/analysis_server/benchmark/integration/main.dart
index 793110d..7cfb299 100644
--- a/pkg/analysis_server/benchmark/integration/main.dart
+++ b/pkg/analysis_server/benchmark/integration/main.dart
@@ -26,7 +26,8 @@
});
PerfArgs args = parseArgs(rawArgs);
- Driver driver = new Driver(logger);
+ Driver driver = new Driver(
+ diagnosticPort: args.diagnosticPort, newTaskModel: args.newTaskModel);
Stream<Operation> stream = openInput(args);
StreamSubscription<Operation> subscription;
subscription = stream.listen((Operation op) {
@@ -56,6 +57,7 @@
const HELP_CMDLINE_OPTION = 'help';
const INPUT_CMDLINE_OPTION = 'input';
const MAP_OPTION = 'map';
+const NEW_TASK_MODEL_OPTION = 'newTaskModel';
/**
* The amount of time to give the server to respond to a shutdown request
@@ -67,6 +69,43 @@
const VERBOSE_CMDLINE_OPTION = 'verbose';
const VERY_VERBOSE_CMDLINE_OPTION = 'vv';
+ArgParser _argParser;
+
+ArgParser get argParser {
+ _argParser = new ArgParser();
+
+ _argParser.addOption(INPUT_CMDLINE_OPTION, abbr: 'i', help: '<filePath>\n'
+ 'The input file specifying how this client should interact with the server.\n'
+ 'If the input file name is "stdin", then the instructions are read from standard input.');
+ _argParser.addOption(MAP_OPTION,
+ abbr: 'm',
+ allowMultiple: true,
+ splitCommas: false,
+ help: '<oldSrcPath>,<newSrcPath>\n'
+ 'This option defines a mapping from the original source directory <oldSrcPath>\n'
+ 'when the instrumentation or log file was generated\n'
+ 'to the target source directory <newSrcPath> used during performance testing.\n'
+ 'Multiple mappings can be specified.\n'
+ 'WARNING: The contents of the target directory will be modified');
+ _argParser.addOption(TMP_SRC_DIR_OPTION, abbr: 't', help: '<dirPath>\n'
+ 'The temporary directory containing source used during performance measurement.\n'
+ 'WARNING: The contents of the target directory will be modified');
+ _argParser.addFlag(NEW_TASK_MODEL_OPTION,
+ help: "enable the use of the new task model",
+ defaultsTo: false,
+ negatable: false);
+ _argParser.addOption(DIAGNOSTIC_PORT_OPTION,
+ abbr: 'd',
+ help: 'localhost port on which server will provide diagnostic web pages');
+ _argParser.addFlag(VERBOSE_CMDLINE_OPTION,
+ abbr: 'v', help: 'Verbose logging', negatable: false);
+ _argParser.addFlag(VERY_VERBOSE_CMDLINE_OPTION,
+ help: 'Extra verbose logging', negatable: false);
+ _argParser.addFlag(HELP_CMDLINE_OPTION,
+ abbr: 'h', help: 'Print this help information', negatable: false);
+ return _argParser;
+}
+
/**
* Open and return the input stream specifying how this client
* should interact with the analysis server.
@@ -79,57 +118,28 @@
} else {
inputRaw = new File(args.inputPath).openRead();
}
- args.srcPathMap.forEach((oldPath, newPath) {
- logger.log(
- Level.INFO, 'mapping source path\n from $oldPath\n to $newPath');
- });
+ for (PathMapEntry entry in args.srcPathMap.entries) {
+ logger.log(Level.INFO, 'mapping source path\n'
+ ' from ${entry.oldSrcPrefix}\n to ${entry.newSrcPrefix}');
+ }
logger.log(Level.INFO, 'tmpSrcDir: ${args.tmpSrcDirPath}');
return inputRaw
.transform(SYSTEM_ENCODING.decoder)
.transform(new LineSplitter())
- .transform(new InputConverter(args.tmpSrcDirPath, args.srcPathMap,
- diagnosticPort: args.diagnosticPort));
+ .transform(new InputConverter(args.tmpSrcDirPath, args.srcPathMap));
}
/**
* Parse the command line arguments.
*/
PerfArgs parseArgs(List<String> rawArgs) {
- ArgParser parser = new ArgParser();
-
- parser.addOption(INPUT_CMDLINE_OPTION, abbr: 'i', help: '<filePath>\n'
- 'The input file specifying how this client should interact with the server.\n'
- 'If the input file name is "stdin", then the instructions are read from standard input.');
- parser.addOption(MAP_OPTION,
- abbr: 'm',
- allowMultiple: true,
- splitCommas: false,
- help: '<oldSrcPath>,<newSrcPath>\n'
- 'This option defines a mapping from the original source directory <oldSrcPath>\n'
- 'when the instrumentation or log file was generated\n'
- 'to the target source directory <newSrcPath> used during performance testing.\n'
- 'Multiple mappings can be specified.\n'
- 'WARNING: The contents of the target directory will be modified');
- parser.addOption(TMP_SRC_DIR_OPTION, abbr: 't', help: '<dirPath>\n'
- 'The temporary directory containing source used during performance measurement.\n'
- 'WARNING: The contents of the target directory will be modified');
- parser.addOption(DIAGNOSTIC_PORT_OPTION,
- abbr: 'd',
- help: 'localhost port on which server will provide diagnostic web pages');
- parser.addFlag(VERBOSE_CMDLINE_OPTION,
- abbr: 'v', help: 'Verbose logging', negatable: false);
- parser.addFlag(VERY_VERBOSE_CMDLINE_OPTION,
- help: 'Extra verbose logging', negatable: false);
- parser.addFlag(HELP_CMDLINE_OPTION,
- abbr: 'h', help: 'Print this help information', negatable: false);
-
ArgResults args;
PerfArgs perfArgs = new PerfArgs();
try {
- args = parser.parse(rawArgs);
+ args = argParser.parse(rawArgs);
} on Exception catch (e) {
print(e);
- printHelp(parser);
+ printHelp();
exit(1);
}
@@ -143,15 +153,14 @@
showHelp = true;
}
- perfArgs.srcPathMap = <String, String>{};
for (String pair in args[MAP_OPTION]) {
if (pair is String) {
int index = pair.indexOf(',');
if (index != -1 && pair.indexOf(',', index + 1) == -1) {
- String oldSrcPath = _withTrailingSeparator(pair.substring(0, index));
- String newSrcPath = _withTrailingSeparator(pair.substring(index + 1));
- if (new Directory(newSrcPath).existsSync()) {
- perfArgs.srcPathMap[oldSrcPath] = newSrcPath;
+ String oldSrcPrefix = _withTrailingSeparator(pair.substring(0, index));
+ String newSrcPrefix = _withTrailingSeparator(pair.substring(index + 1));
+ if (new Directory(newSrcPrefix).existsSync()) {
+ perfArgs.srcPathMap.add(oldSrcPrefix, newSrcPrefix);
continue;
}
}
@@ -166,6 +175,8 @@
showHelp = true;
}
+ perfArgs.newTaskModel = args[NEW_TASK_MODEL_OPTION];
+
String portText = args[DIAGNOSTIC_PORT_OPTION];
if (portText != null) {
perfArgs.diagnosticPort = int.parse(portText, onError: (s) {
@@ -183,18 +194,18 @@
}
if (showHelp) {
- printHelp(parser);
+ printHelp();
exit(1);
}
return perfArgs;
}
-void printHelp(ArgParser parser) {
+void printHelp() {
print('');
print('Launch and interact with the AnalysisServer');
print('');
- print(parser.usage);
+ print(argParser.usage);
}
/**
@@ -226,7 +237,7 @@
* when the instrumentation or log file was generated
* to the target source directory used during performance testing.
*/
- Map<String, String> srcPathMap;
+ final PathMap srcPathMap = new PathMap();
/**
* The temporary directory containing source used during performance measurement.
@@ -237,4 +248,9 @@
* The diagnostic port for Analysis Server or `null` if none.
*/
int diagnosticPort;
+
+ /**
+ * `true` if the server should run using the new task model.
+ */
+ bool newTaskModel;
}
diff --git a/pkg/analysis_server/benchmark/integration/operation.dart b/pkg/analysis_server/benchmark/integration/operation.dart
index f9ee62a..9e408d8 100644
--- a/pkg/analysis_server/benchmark/integration/operation.dart
+++ b/pkg/analysis_server/benchmark/integration/operation.dart
@@ -111,7 +111,7 @@
* A [ResponseOperation] waits for a [JSON] response from the server.
*/
class ResponseOperation extends Operation {
- static final Duration responseTimeout = new Duration(seconds: 5);
+ static final Duration responseTimeout = new Duration(seconds: 60);
final CommonInputConverter converter;
final Map<String, dynamic> requestJson;
final Map<String, dynamic> responseJson;
@@ -169,6 +169,7 @@
'expected error:${format(expectedError)}\n'
'but received:${format(actualResult)}';
driver.results.recordUnexpectedResults(requestJson['method']);
+ converter.logOverlayContent();
if (expectedError == null) {
converter.logger.log(Level.SEVERE, message);
} else {
@@ -179,13 +180,9 @@
}
class StartServerOperation extends Operation {
- final int diagnosticPort;
-
- StartServerOperation({this.diagnosticPort});
-
@override
Future perform(Driver driver) {
- return driver.startServer(diagnosticPort: diagnosticPort);
+ return driver.startServer();
}
}
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 8d2995c..815a2d3 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -1575,6 +1575,7 @@
+
<h3>Requests</h3><dl><dt class="request"><a name="request_edit.format">edit.format</a> (<a href="#request_edit.format">#</a>)</dt><dd><div class="box"><pre>request: {
"id": String
"method": "edit.format"
@@ -1940,6 +1941,48 @@
The file edit that is to be applied to the given file to effect
the sorting.
</p>
+ </dd></dl></dd><dt class="request"><a name="request_edit.organizeDirectives">edit.organizeDirectives</a> (<a href="#request_edit.organizeDirectives">#</a>)</dt><dd><div class="box"><pre>request: {
+ "id": String
+ "method": "edit.organizeDirectives"
+ "params": {
+ "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+ }
+}</pre><br><pre>response: {
+ "id": String
+ "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+ "result": {
+ "<b>edit</b>": <a href="#type_SourceFileEdit">SourceFileEdit</a>
+ }
+}</pre></div>
+ <p>
+ Organizes all of the directives - removes unused imports and sorts
+ directives of the given Dart file according to the
+ <a href="https://www.dartlang.org/articles/style-guide/">Dart Style Guide</a>.
+ </p>
+ <p>
+ If a request is made for a file that does not exist, does not belong
+ to an analysis root or is not a Dart file,
+ <tt>FILE_NOT_ANALYZED</tt> will be generated.
+ </p>
+ <p>
+ If directives of the Dart file cannot be organized, for example
+ because it has scan or parse errors, or by other reasons,
+ <tt>ORGANIZE_DIRECTIVES_ERROR</tt> will be generated. The message
+ will provide datails about the reason.
+ </p>
+
+
+ <h4>Parameters</h4><dl><dt class="field"><b><i>file ( <a href="#type_FilePath">FilePath</a> )</i></b></dt><dd>
+
+ <p>
+ The Dart file to organize directives in.
+ </p>
+ </dd></dl><h4>Returns</h4><dl><dt class="field"><b><i>edit ( <a href="#type_SourceFileEdit">SourceFileEdit</a> )</i></b></dt><dd>
+
+ <p>
+ The file edit that is to be applied to the given file to effect
+ the organizing.
+ </p>
</dd></dl></dd></dl>
<h2 class="domain"><a name="domain_execution">Domain: execution</a></h2>
<p>
@@ -2289,27 +2332,28 @@
<dl><dt class="field"><b><i>enableAsync ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
- <p><b><i>Deprecated</i></b></p>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed async feature.
</p>
</dd><dt class="field"><b><i>enableDeferredLoading ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
- <p><b><i>Deprecated</i></b></p>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed deferred loading feature.
</p>
</dd><dt class="field"><b><i>enableEnums ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
- <p><b><i>Deprecated</i></b></p>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed enum feature.
</p>
</dd><dt class="field"><b><i>enableNullAwareOperators ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed "null aware operators" feature.
@@ -3359,6 +3403,13 @@
not be satisfied because the content of the file changed before
the requested results could be computed.
</p>
+ </dd><dt class="value">FILE_NOT_ANALYZED</dt><dd>
+
+ <p>
+ A request specified a FilePath which does not match a file in
+ an analysis root, or the requested operation is not available
+ for the file.
+ </p>
</dd><dt class="value">FORMAT_INVALID_FILE</dt><dd>
<p>
@@ -3381,7 +3432,7 @@
</dd><dt class="value">GET_NAVIGATION_INVALID_FILE</dt><dd>
<p>
- An "analysis.getErrors" request specified a FilePath
+ An "analysis.getNavigation" request specified a FilePath
which does not match a file currently subject to
analysis.
</p>
@@ -3421,6 +3472,12 @@
The "--no-index" flag was passed when the analysis server created,
but this API call requires an index to have been generated.
</p>
+ </dd><dt class="value">ORGANIZE_DIRECTIVES_ERROR</dt><dd>
+
+ <p>
+ An "edit.organizeDirectives" request specified a Dart file that
+ cannot be analyzed. The reason is described in the message.
+ </p>
</dd><dt class="value">REFACTORING_REQUEST_CANCELLED</dt><dd>
<p>
diff --git a/pkg/analysis_server/lib/edit/fix/fix_core.dart b/pkg/analysis_server/lib/edit/fix/fix_core.dart
index f546198..f38d59a 100644
--- a/pkg/analysis_server/lib/edit/fix/fix_core.dart
+++ b/pkg/analysis_server/lib/edit/fix/fix_core.dart
@@ -5,6 +5,7 @@
library analysis_server.edit.fix.fix_core;
import 'package:analysis_server/src/protocol.dart' show SourceChange;
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -24,7 +25,8 @@
* relevant fixes will be sorted before fixes with a lower relevance.
*/
static final Comparator<Fix> SORT_BY_RELEVANCE = (Fix firstFix,
- Fix secondFix) => firstFix.kind.relevance - secondFix.kind.relevance;
+ Fix secondFix) =>
+ firstFix.kind.relevance - secondFix.kind.relevance;
/**
* A description of the fix being proposed.
@@ -59,7 +61,8 @@
* Return a list of fixes for the given [error]. The error was reported
* after it's source was analyzed in the given [context].
*/
- List<Fix> computeFixes(AnalysisContext context, AnalysisError error);
+ List<Fix> computeFixes(ResourceProvider resourceProvider,
+ AnalysisContext context, AnalysisError error);
}
/**
diff --git a/pkg/analysis_server/lib/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/edit/fix/fix_dart.dart
index 0e559e4..c009e68 100644
--- a/pkg/analysis_server/lib/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/edit/fix/fix_dart.dart
@@ -5,6 +5,7 @@
library analysis_server.edit.fix.fix_dart;
import 'package:analysis_server/edit/fix/fix_core.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -18,7 +19,8 @@
*/
abstract class DartFixContributor extends FixContributor {
@override
- List<Fix> computeFixes(AnalysisContext context, AnalysisError error) {
+ List<Fix> computeFixes(ResourceProvider resourceProvider,
+ AnalysisContext context, AnalysisError error) {
Source source = error.source;
if (!AnalysisEngine.isDartFileName(source.fullName)) {
return Fix.EMPTY_LIST;
@@ -32,12 +34,13 @@
if (unit == null) {
return Fix.EMPTY_LIST;
}
- return internalComputeFixes(unit, error);
+ return internalComputeFixes(resourceProvider, unit, error);
}
/**
* Return a list of fixes for the given [error]. The error was reported
* against the given compilation [unit].
*/
- List<Fix> internalComputeFixes(CompilationUnit unit, AnalysisError error);
+ List<Fix> internalComputeFixes(ResourceProvider resourceProvider,
+ CompilationUnit unit, AnalysisError error);
}
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 57fd203..21a0f7e 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -21,12 +21,10 @@
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
import 'package:analysis_server/uri/resolver_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
-import 'package:analyzer/source/package_map_resolver.dart';
-import 'package:analyzer/source/sdk_ext.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -35,7 +33,6 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:package_config/packages.dart';
import 'package:plugin/plugin.dart';
typedef void OptionUpdater(AnalysisOptionsImpl options);
@@ -117,7 +114,7 @@
* The [ContextManager] that handles the mapping from analysis roots to
* context directories.
*/
- ServerContextManager contextManager;
+ ContextManager contextManager;
/**
* A flag indicating whether the server is running. When false, contexts
@@ -272,6 +269,17 @@
Set<String> prevAnalyzedFiles;
/**
+ * The default options used to create new analysis contexts.
+ */
+ AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl();
+
+ /**
+ * The controller for sending [ContextsChangedEvent]s.
+ */
+ StreamController<ContextsChangedEvent> _onContextsChangedController =
+ new StreamController<ContextsChangedEvent>.broadcast();
+
+ /**
* Initialize a newly created server to receive requests from and send
* responses to the given [channel].
*
@@ -284,9 +292,9 @@
* running a full analysis server.
*/
AnalysisServer(this.channel, this.resourceProvider,
- OptimizingPubPackageMapProvider packageMapProvider, Index _index,
- this.serverPlugin, this.options, this.defaultSdk,
- this.instrumentationService, {ContextManager contextManager: null,
+ PubPackageMapProvider packageMapProvider, Index _index, this.serverPlugin,
+ this.options, this.defaultSdk, this.instrumentationService,
+ {ContextManager contextManager: null,
ResolverProvider packageResolverProvider: null,
this.rethrowExceptions: true})
: index = _index,
@@ -294,20 +302,18 @@
_performance = performanceDuringStartup;
operationQueue = new ServerOperationQueue();
if (contextManager == null) {
- contextManager = new ServerContextManager(this, resourceProvider,
+ contextManager = new ContextManagerImpl(resourceProvider,
packageResolverProvider, packageMapProvider, instrumentationService);
- AnalysisOptionsImpl analysisOptions =
- (contextManager as ServerContextManager).defaultOptions;
- analysisOptions.incremental = true;
- analysisOptions.incrementalApi = options.enableIncrementalResolutionApi;
- analysisOptions.incrementalValidation =
- options.enableIncrementalResolutionValidation;
- analysisOptions.generateImplicitErrors = false;
- } else if (contextManager is! ServerContextManager) {
- // TODO(brianwilkerson) Remove this when the interface is complete.
- throw new StateError(
- 'The contextManager must be an instance of ServerContextManager');
}
+ ServerContextManagerCallbacks contextManagerCallbacks =
+ new ServerContextManagerCallbacks(this, resourceProvider);
+ contextManager.callbacks = contextManagerCallbacks;
+ defaultContextOptions.incremental = true;
+ defaultContextOptions.incrementalApi =
+ options.enableIncrementalResolutionApi;
+ defaultContextOptions.incrementalValidation =
+ options.enableIncrementalResolutionValidation;
+ defaultContextOptions.generateImplicitErrors = false;
this.contextManager = contextManager;
_noErrorNotification = options.noErrorNotification;
AnalysisEngine.instance.logger = new AnalysisLogger();
@@ -353,7 +359,7 @@
* The stream that is notified when contexts are added or removed.
*/
Stream<ContextsChangedEvent> get onContextsChanged =>
- contextManager.onContextsChanged;
+ _onContextsChangedController.stream;
/**
* The stream that is notified when a single file has been analyzed.
@@ -497,15 +503,14 @@
{
AnalysisContext containingContext = getContainingContext(path);
if (containingContext != null) {
- Source source = AbstractContextManager.createSourceInContext(
- containingContext, file);
+ Source source =
+ ContextManagerImpl.createSourceInContext(containingContext, file);
return new ContextSourcePair(containingContext, source);
}
}
// try to find a context that analysed the file
for (AnalysisContext context in folderMap.values) {
- Source source =
- AbstractContextManager.createSourceInContext(context, file);
+ Source source = ContextManagerImpl.createSourceInContext(context, file);
SourceKind kind = context.getKindOf(source);
if (kind != SourceKind.UNKNOWN) {
return new ContextSourcePair(context, source);
@@ -1025,8 +1030,8 @@
Uri uri = context.sourceFactory.restoreUri(source);
if (uri.scheme != 'file') {
preferredContext = context;
- source = AbstractContextManager.createSourceInContext(
- context, resource);
+ source =
+ ContextManagerImpl.createSourceInContext(context, resource);
break;
}
}
@@ -1226,15 +1231,14 @@
//
// Update the defaults used to create new contexts.
//
- AnalysisOptionsImpl options = contextManager.defaultOptions;
optionUpdaters.forEach((OptionUpdater optionUpdater) {
- optionUpdater(options);
+ optionUpdater(defaultContextOptions);
});
}
/**
- * Return a set of contexts containing all of the resources in the given list
- * of [resources].
+ * Return a set of all contexts whose associated folder is contained within,
+ * or equal to, one of the resources in the given list of [resources].
*/
Set<AnalysisContext> _getContexts(List<Resource> resources) {
Set<AnalysisContext> contexts = new HashSet<AnalysisContext>();
@@ -1337,45 +1341,26 @@
PriorityChangeEvent(this.firstSource);
}
-class ServerContextManager extends AbstractContextManager {
+class ServerContextManagerCallbacks extends ContextManagerCallbacks {
final AnalysisServer analysisServer;
/**
- * The default options used to create new analysis contexts.
+ * The [ResourceProvider] by which paths are converted into [Resource]s.
*/
- AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+ final ResourceProvider resourceProvider;
- /**
- * The controller for sending [ContextsChangedEvent]s.
- */
- StreamController<ContextsChangedEvent> _onContextsChangedController;
-
- ServerContextManager(this.analysisServer, ResourceProvider resourceProvider,
- ResolverProvider packageResolverProvider,
- OptimizingPubPackageMapProvider packageMapProvider,
- InstrumentationService service)
- : super(resourceProvider, packageResolverProvider, packageMapProvider,
- service) {
- _onContextsChangedController =
- new StreamController<ContextsChangedEvent>.broadcast();
- }
-
- /**
- * The stream that is notified when contexts are added or removed.
- */
- Stream<ContextsChangedEvent> get onContextsChanged =>
- _onContextsChangedController.stream;
+ ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider);
@override
- AnalysisContext addContext(
- Folder folder, UriResolver packageUriResolver, Packages packages) {
+ AnalysisContext addContext(Folder folder, FolderDisposition disposition) {
InternalAnalysisContext context =
AnalysisEngine.instance.createAnalysisContext();
context.contentCache = analysisServer.overlayState;
analysisServer.folderMap[folder] = context;
- context.sourceFactory = _createSourceFactory(packageUriResolver, packages);
- context.analysisOptions = new AnalysisOptionsImpl.from(defaultOptions);
- _onContextsChangedController
+ context.sourceFactory = _createSourceFactory(disposition);
+ context.analysisOptions =
+ new AnalysisOptionsImpl.from(analysisServer.defaultContextOptions);
+ analysisServer._onContextsChangedController
.add(new ContextsChangedEvent(added: [context]));
analysisServer.schedulePerformAnalysisOperation(context);
return context;
@@ -1406,20 +1391,15 @@
}
@override
- void removeContext(Folder folder) {
+ void removeContext(Folder folder, List<String> flushedFiles) {
AnalysisContext context = analysisServer.folderMap.remove(folder);
-
- // See dartbug.com/22689, the AnalysisContext is computed in
- // computeFlushedFiles instead of using the referenced context above, this
- // is an attempt to be careful concerning the referenced issue.
- List<String> flushedFiles = computeFlushedFiles(folder);
sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
if (analysisServer.index != null) {
analysisServer.index.removeContext(context);
}
analysisServer.operationQueue.contextRemoved(context);
- _onContextsChangedController
+ analysisServer._onContextsChangedController
.add(new ContextsChangedEvent(removed: [context]));
analysisServer.sendContextAnalysisDoneNotifications(
context, AnalysisDoneReason.CONTEXT_REMOVED);
@@ -1446,10 +1426,10 @@
@override
void updateContextPackageUriResolver(
- Folder contextFolder, UriResolver packageUriResolver, Packages packages) {
+ Folder contextFolder, FolderDisposition disposition) {
AnalysisContext context = analysisServer.folderMap[contextFolder];
- context.sourceFactory = _createSourceFactory(packageUriResolver, packages);
- _onContextsChangedController
+ context.sourceFactory = _createSourceFactory(disposition);
+ analysisServer._onContextsChangedController
.add(new ContextsChangedEvent(changed: [context]));
analysisServer.schedulePerformAnalysisOperation(context);
}
@@ -1463,25 +1443,17 @@
}
/**
- * Set up a [SourceFactory] that resolves packages using the given
- * [packageUriResolver] and [packages] resolution strategy.
+ * Set up a [SourceFactory] that resolves packages as appropriate for the
+ * given [disposition].
*/
- SourceFactory _createSourceFactory(
- UriResolver packageUriResolver, Packages packages) {
+ SourceFactory _createSourceFactory(FolderDisposition disposition) {
UriResolver dartResolver = new DartUriResolver(analysisServer.defaultSdk);
UriResolver resourceResolver = new ResourceUriResolver(resourceProvider);
List<UriResolver> resolvers = [];
resolvers.add(dartResolver);
- if (packageUriResolver is PackageMapUriResolver) {
- UriResolver sdkExtResolver =
- new SdkExtUriResolver(packageUriResolver.packageMap);
- resolvers.add(sdkExtResolver);
- }
- if (packageUriResolver != null) {
- resolvers.add(packageUriResolver);
- }
+ resolvers.addAll(disposition.createPackageUriResolvers(resourceProvider));
resolvers.add(resourceResolver);
- return new SourceFactory(resolvers, packages);
+ return new SourceFactory(resolvers, disposition.packages);
}
}
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index b4acd97..f37446b 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -79,6 +79,7 @@
const String EDIT_GET_AVAILABLE_REFACTORINGS = 'edit.getAvailableRefactorings';
const String EDIT_GET_FIXES = 'edit.getFixes';
const String EDIT_GET_REFACTORING = 'edit.getRefactoring';
+const String EDIT_ORGANIZE_DIRECTIVES = 'edit.organizeDirectives';
const String EDIT_SORT_MEMBERS = 'edit.sortMembers';
//
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index fb1c3b4..41fb266 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -10,13 +10,15 @@
import 'dart:core' hide Resource;
import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
+import 'package:analysis_server/src/server_options.dart';
import 'package:analysis_server/uri/resolver_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/source/package_map_provider.dart';
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/source/path_filter.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -29,15 +31,287 @@
import 'package:yaml/yaml.dart';
/**
+ * Information tracked by the [ContextManager] for each context.
+ */
+class ContextInfo {
+ /**
+ * The [ContextManager] which is tracking this information.
+ */
+ final ContextManagerImpl contextManager;
+
+ /**
+ * The [Folder] for which this information object is created.
+ */
+ final Folder folder;
+
+ /// The [PathFilter] used to filter sources from being analyzed.
+ final PathFilter pathFilter;
+
+ /**
+ * The enclosed pubspec-based contexts.
+ */
+ final List<ContextInfo> children = <ContextInfo>[];
+
+ /**
+ * The package root for this context, or null if there is no package root.
+ */
+ String packageRoot;
+
+ /**
+ * The [ContextInfo] that encloses this one, or `null` if this is the virtual
+ * [ContextInfo] object that acts as the ancestor of all other [ContextInfo]
+ * objects.
+ */
+ ContextInfo parent;
+
+ /**
+ * The package description file path for this context.
+ */
+ String packageDescriptionPath;
+
+ /**
+ * Paths to files which determine the folder disposition and package map.
+ *
+ * TODO(paulberry): if any of these files are outside of [folder], they won't
+ * be watched for changes. I believe the use case for watching these files
+ * is no longer relevant.
+ */
+ Set<String> _dependencies = new Set<String>();
+
+ /**
+ * The analysis context that was created for the [folder].
+ */
+ AnalysisContext context;
+
+ /**
+ * Map from full path to the [Source] object, for each source that has been
+ * added to the context.
+ */
+ Map<String, Source> sources = new HashMap<String, Source>();
+
+ ContextInfo(ContextManagerImpl contextManager, this.parent, Folder folder,
+ File packagespecFile, this.packageRoot)
+ : contextManager = contextManager,
+ folder = folder,
+ pathFilter = new PathFilter(
+ contextManager.resourceProvider.pathContext, folder.path, null) {
+ packageDescriptionPath = packagespecFile.path;
+ parent.children.add(this);
+ }
+
+ /**
+ * Create the virtual [ContextInfo] which acts as an ancestor to all other
+ * [ContextInfo]s.
+ */
+ ContextInfo._root()
+ : contextManager = null,
+ folder = null,
+ pathFilter = null;
+
+ /**
+ * Iterate through all [children] and their children, recursively.
+ */
+ Iterable<ContextInfo> get descendants sync* {
+ for (ContextInfo child in children) {
+ yield child;
+ yield* child.descendants;
+ }
+ }
+
+ /**
+ * Returns `true` if this is a "top level" context, meaning that the folder
+ * associated with it is not contained within any other folders that have an
+ * associated context.
+ */
+ bool get isTopLevel => parent.parent == null;
+
+ /**
+ * Returns `true` if [path] is excluded, as it is in one of the children.
+ */
+ bool excludes(String path) {
+ return children.any((child) {
+ return child.folder.contains(path);
+ });
+ }
+
+ /**
+ * Returns `true` if [resource] is excluded, as it is in one of the children.
+ */
+ bool excludesResource(Resource resource) => excludes(resource.path);
+
+ /**
+ * Return the first [ContextInfo] in [children] whose associated folder is or
+ * contains [path]. If there is no such [ContextInfo], return `null`.
+ */
+ ContextInfo findChildInfoFor(String path) {
+ for (ContextInfo info in children) {
+ if (info.folder.isOrContains(path)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Determine if the given [path] is one of the dependencies most recently
+ * passed to [setDependencies].
+ */
+ bool hasDependency(String path) => _dependencies.contains(path);
+
+ /// Returns `true` if [path] should be ignored.
+ bool ignored(String path) => pathFilter.ignored(path);
+
+ /**
+ * Returns `true` if [path] is the package description file for this context
+ * (pubspec.yaml or .packages).
+ */
+ bool isPathToPackageDescription(String path) =>
+ path == packageDescriptionPath;
+
+ /**
+ * Update the set of dependencies for this context.
+ */
+ void setDependencies(Iterable<String> newDependencies) {
+ _dependencies = newDependencies.toSet();
+ }
+}
+
+/**
* Class that maintains a mapping from included/excluded paths to a set of
* folders that should correspond to analysis contexts.
*/
-abstract class AbstractContextManager implements ContextManager {
+abstract class ContextManager {
+ // TODO(brianwilkerson) Support:
+ // setting the default analysis options
+ // setting the default content cache
+ // setting the default SDK
+ // maintaining AnalysisContext.folderMap (or remove it)
+ // telling server when a context has been added or removed (see onContextsChanged)
+ // telling server when a context needs to be re-analyzed
+ // notifying the client when results should be flushed
+ // using analyzeFileFunctions to determine which files to analyze
+ //
+ // TODO(brianwilkerson) Move this class to a public library.
/**
+ * Get the callback interface used to create, destroy, and update contexts.
+ */
+ ContextManagerCallbacks get callbacks;
+
+ /**
+ * Set the callback interface used to create, destroy, and update contexts.
+ */
+ void set callbacks(ContextManagerCallbacks value);
+
+ /**
+ * Return the list of excluded paths (folders and files) most recently passed
+ * to [setRoots].
+ */
+ List<String> get excludedPaths;
+
+ /**
+ * Return the list of included paths (folders and files) most recently passed
+ * to [setRoots].
+ */
+ List<String> get includedPaths;
+
+ /**
+ * Return a list of all of the contexts reachable from the given
+ * [analysisRoot] (the context associated with [analysisRoot] and all of its
+ * descendants).
+ */
+ List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot);
+
+ /**
+ * Return `true` if the given absolute [path] is in one of the current
+ * root folders and is not excluded.
+ */
+ bool isInAnalysisRoot(String path);
+
+ /**
+ * Rebuild the set of contexts from scratch based on the data last sent to
+ * [setRoots]. Only contexts contained in the given list of analysis [roots]
+ * will be rebuilt, unless the list is `null`, in which case every context
+ * will be rebuilt.
+ */
+ void refresh(List<Resource> roots);
+
+ /**
+ * Change the set of paths which should be used as starting points to
+ * determine the context directories.
+ */
+ void setRoots(List<String> includedPaths, List<String> excludedPaths,
+ Map<String, String> packageRoots);
+}
+
+/**
+ * Callback interface used by [ContextManager] to (a) request that contexts be
+ * created, destroyed or updated, (b) inform the client when "pub list"
+ * operations are in progress, and (c) determine which files should be
+ * analyzed.
+ *
+ * TODO(paulberry): eliminate this interface, and instead have [ContextManager]
+ * operations return data structures describing how context state should be
+ * modified.
+ */
+abstract class ContextManagerCallbacks {
+ /**
+ * Create and return a new analysis context, allowing [disposition] to govern
+ * details of how the context is to be created.
+ */
+ AnalysisContext addContext(Folder folder, FolderDisposition disposition);
+
+ /**
+ * Called when the set of files associated with a context have changed (or
+ * some of those files have been modified). [changeSet] is the set of
+ * changes that need to be applied to the context.
+ */
+ void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
+
+ /**
+ * Called when the ContextManager is about to start computing the package
+ * map.
+ */
+ void beginComputePackageMap() {
+ // By default, do nothing.
+ }
+
+ /**
+ * Called when the ContextManager has finished computing the package map.
+ */
+ void endComputePackageMap() {
+ // By default, do nothing.
+ }
+
+ /**
+ * 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).
+ */
+ void removeContext(Folder folder, List<String> flushedFiles);
+
+ /**
+ * Return `true` if the given [file] should be analyzed.
+ */
+ bool shouldFileBeAnalyzed(File file);
+
+ /**
+ * Called when the disposition for a context has changed.
+ */
+ void updateContextPackageUriResolver(
+ Folder contextFolder, FolderDisposition disposition);
+}
+
+/**
+ * Class that maintains a mapping from included/excluded paths to a set of
+ * folders that should correspond to analysis contexts.
+ */
+class ContextManagerImpl implements ContextManager {
+ /**
* Temporary flag to hide WIP .packages support (DEP 5).
*/
- static bool ENABLE_PACKAGESPEC_SUPPORT = false;
+ static bool ENABLE_PACKAGESPEC_SUPPORT = serverOptions.isSet(
+ 'ContextManagerImpl.ENABLE_PACKAGESPEC_SUPPORT', defaultValue: true);
/**
* The name of the `lib` directory.
@@ -60,12 +334,6 @@
static const String PACKAGE_SPEC_NAME = '.packages';
/**
- * [_ContextInfo] object for each included directory in the most
- * recent successful call to [setRoots].
- */
- Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>();
-
- /**
* The [ResourceProvider] using which paths are converted into [Resource]s.
*/
final ResourceProvider resourceProvider;
@@ -109,7 +377,7 @@
* Provider which is used to determine the mapping from package name to
* package folder.
*/
- final OptimizingPubPackageMapProvider _packageMapProvider;
+ final PubPackageMapProvider _packageMapProvider;
/// Provider of analysis options.
AnalysisOptionsProvider analysisOptionsProvider =
@@ -120,70 +388,59 @@
*/
final InstrumentationService _instrumentationService;
- AbstractContextManager(this.resourceProvider, this.packageResolverProvider,
+ @override
+ ContextManagerCallbacks callbacks;
+
+ /**
+ * Virtual [ContextInfo] which acts as the ancestor of all other
+ * [ContextInfo]s.
+ */
+ final ContextInfo _rootInfo = new ContextInfo._root();
+
+ /**
+ * Stream subscription we are using to watch each analysis root directory for
+ * changes.
+ */
+ final Map<Folder, StreamSubscription<WatchEvent>> _changeSubscriptions =
+ <Folder, StreamSubscription<WatchEvent>>{};
+
+ ContextManagerImpl(this.resourceProvider, this.packageResolverProvider,
this._packageMapProvider, this._instrumentationService) {
pathContext = resourceProvider.pathContext;
}
- /**
- * Create and return a new analysis context.
- */
- AnalysisContext addContext(
- Folder folder, UriResolver packageUriResolver, Packages packages);
-
- /**
- * Called when the set of files associated with a context have changed (or
- * some of those files have been modified). [changeSet] is the set of
- * changes that need to be applied to the context.
- */
- void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
-
- /**
- * We are about to start computing the package map.
- */
- void beginComputePackageMap() {
- // Do nothing.
- }
-
- /**
- * Compute the set of files that are being flushed, this is defined as
- * the set of sources in the removed context (context.sources), that are
- * orphaned by this context being removed (no other context includes this
- * file.)
- */
- List<String> computeFlushedFiles(Folder folder) {
- AnalysisContext context = _contexts[folder].context;
- HashSet<String> flushedFiles = new HashSet<String>();
- for (Source source in context.sources) {
- flushedFiles.add(source.fullName);
- }
- for (_ContextInfo contextInfo in _contexts.values) {
- AnalysisContext contextN = contextInfo.context;
- if (context != contextN) {
- for (Source source in contextN.sources) {
- flushedFiles.remove(source.fullName);
- }
- }
- }
- return flushedFiles.toList(growable: false);
- }
-
@override
List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
List<AnalysisContext> contexts = <AnalysisContext>[];
- _contexts.forEach((Folder contextFolder, _ContextInfo info) {
- if (analysisRoot.isOrContains(contextFolder.path)) {
- contexts.add(info.context);
+ ContextInfo innermostContainingInfo =
+ _getInnermostContextInfoFor(analysisRoot.path);
+ void addContextAndDescendants(ContextInfo info) {
+ contexts.add(info.context);
+ info.children.forEach(addContextAndDescendants);
+ }
+ if (innermostContainingInfo != null) {
+ if (analysisRoot == innermostContainingInfo.folder) {
+ addContextAndDescendants(innermostContainingInfo);
+ } else {
+ for (ContextInfo info in innermostContainingInfo.children) {
+ if (analysisRoot.isOrContains(info.folder.path)) {
+ addContextAndDescendants(info);
+ }
+ }
}
- });
+ }
return contexts;
}
/**
- * We have finished computing the package map.
+ * For testing: get the [ContextInfo] object for the given [folder], if any.
*/
- void endComputePackageMap() {
- // Do nothing.
+ ContextInfo getContextInfoFor(Folder folder) {
+ ContextInfo info = _getInnermostContextInfoFor(folder.path);
+ if (folder == info.folder) {
+ return info;
+ }
+ return null;
}
@override
@@ -192,9 +449,9 @@
if (_isExcluded(path)) {
return false;
}
- // check if in of the roots
- for (Folder root in _contexts.keys) {
- if (root.contains(path)) {
+ // check if in one of the roots
+ for (ContextInfo info in _rootInfo.children) {
+ if (info.folder.contains(path)) {
return true;
}
}
@@ -202,12 +459,11 @@
return false;
}
- /// Process [options] for the context [folder].
- void processOptionsForContext(Folder folder, Map<String, YamlNode> options) {
- _ContextInfo info = _contexts[folder];
- if (info == null) {
- return;
- }
+ /**
+ * Process [options] for the context having info [info].
+ */
+ void processOptionsForContext(
+ ContextInfo info, Map<String, YamlNode> options) {
YamlMap analyzer = options['analyzer'];
if (analyzer == null) {
// No options for analyzer.
@@ -217,21 +473,22 @@
// Set ignore patterns.
YamlList exclude = analyzer['exclude'];
if (exclude != null) {
- setIgnorePatternsForContext(folder, exclude);
+ setIgnorePatternsForContext(info, exclude);
}
}
@override
void refresh(List<Resource> roots) {
// Destroy old contexts
- List<Folder> contextFolders = _contexts.keys.toList();
+ List<ContextInfo> contextInfos = _rootInfo.descendants.toList();
if (roots == null) {
- contextFolders.forEach(_destroyContext);
+ contextInfos.forEach(_destroyContext);
} else {
roots.forEach((Resource resource) {
- contextFolders.forEach((Folder contextFolder) {
- if (resource is Folder && resource.isOrContains(contextFolder.path)) {
- _destroyContext(contextFolder);
+ contextInfos.forEach((ContextInfo contextInfo) {
+ if (resource is Folder &&
+ resource.isOrContains(contextInfo.folder.path)) {
+ _destroyContext(contextInfo);
}
});
});
@@ -242,18 +499,11 @@
}
/**
- * Remove the context associated with the given [folder].
+ * Sets the [ignorePatterns] for the context having info [info].
*/
- void removeContext(Folder folder);
-
- /// Sets the [ignorePatterns] for the context [folder].
- void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) {
- _ContextInfo info = _contexts[folder];
- if (info == null) {
- return;
- }
- var pathFilter = info.pathFilter;
- pathFilter.setIgnorePatterns(ignorePatterns);
+ void setIgnorePatternsForContext(
+ ContextInfo info, List<String> ignorePatterns) {
+ info.pathFilter.setIgnorePatterns(ignorePatterns);
}
@override
@@ -271,7 +521,7 @@
}
});
- List<Folder> contextFolders = _contexts.keys.toList();
+ List<ContextInfo> contextInfos = _rootInfo.descendants.toList();
// included
Set<Folder> includedFolders = new HashSet<Folder>();
for (int i = 0; i < includedPaths.length; i++) {
@@ -290,33 +540,35 @@
List<String> oldExcludedPaths = this.excludedPaths;
this.excludedPaths = excludedPaths;
// destroy old contexts
- for (Folder contextFolder in contextFolders) {
+ for (ContextInfo contextInfo in contextInfos) {
bool isIncluded = includedFolders.any((folder) {
- return folder.isOrContains(contextFolder.path);
+ return folder.isOrContains(contextInfo.folder.path);
});
if (!isIncluded) {
- _destroyContext(contextFolder);
+ _destroyContext(contextInfo);
}
}
// Update package roots for existing contexts
- _contexts.forEach((Folder folder, _ContextInfo info) {
- String newPackageRoot = normalizedPackageRoots[folder.path];
+ for (ContextInfo info in _rootInfo.descendants) {
+ String newPackageRoot = normalizedPackageRoots[info.folder.path];
if (info.packageRoot != newPackageRoot) {
info.packageRoot = newPackageRoot;
- _recomputePackageUriResolver(info);
+ _recomputeFolderDisposition(info);
}
- });
+ }
// create new contexts
for (Folder includedFolder in includedFolders) {
- bool wasIncluded = contextFolders.any((folder) {
- return folder.isOrContains(includedFolder.path);
+ bool wasIncluded = contextInfos.any((info) {
+ return info.folder.isOrContains(includedFolder.path);
});
if (!wasIncluded) {
- _createContexts(includedFolder, false);
+ _changeSubscriptions[includedFolder] =
+ includedFolder.changes.listen(_handleWatchEvent);
+ _createContexts(_rootInfo, includedFolder, false);
}
}
// remove newly excluded sources
- _contexts.forEach((folder, info) {
+ for (ContextInfo info in _rootInfo.descendants) {
// prepare excluded sources
Map<String, Source> excludedSources = new HashMap<String, Source>();
info.sources.forEach((String path, Source source) {
@@ -331,31 +583,21 @@
info.sources.remove(path);
changeSet.removedSource(source);
});
- applyChangesToContext(folder, changeSet);
- });
+ callbacks.applyChangesToContext(info.folder, changeSet);
+ }
// add previously excluded sources
- _contexts.forEach((folder, info) {
+ for (ContextInfo info in _rootInfo.descendants) {
ChangeSet changeSet = new ChangeSet();
- _addPreviouslyExcludedSources(info, changeSet, folder, oldExcludedPaths);
- applyChangesToContext(folder, changeSet);
- });
+ _addPreviouslyExcludedSources(
+ info, changeSet, info.folder, oldExcludedPaths);
+ callbacks.applyChangesToContext(info.folder, changeSet);
+ }
}
/**
- * Return `true` if the given [file] should be analyzed.
- */
- bool shouldFileBeAnalyzed(File file);
-
- /**
- * Called when the package map for a context has changed.
- */
- void updateContextPackageUriResolver(
- Folder contextFolder, UriResolver packageUriResolver, Packages packages);
-
- /**
* Resursively adds all Dart and HTML files to the [changeSet].
*/
- void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet,
+ void _addPreviouslyExcludedSources(ContextInfo info, ChangeSet changeSet,
Folder folder, List<String> oldExcludedPaths) {
if (info.excludesResource(folder)) {
return;
@@ -377,7 +619,7 @@
// add files, recurse into folders
if (child is File) {
// ignore if should not be analyzed at all
- if (!shouldFileBeAnalyzed(child)) {
+ if (!callbacks.shouldFileBeAnalyzed(child)) {
continue;
}
// ignore if was not excluded
@@ -402,7 +644,7 @@
/**
* Resursively adds all Dart and HTML files to the [changeSet].
*/
- void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) {
+ void _addSourceFiles(ChangeSet changeSet, Folder folder, ContextInfo info) {
if (info.excludesResource(folder) || folder.shortName.startsWith('.')) {
return;
}
@@ -422,7 +664,7 @@
}
// add files, recurse into folders
if (child is File) {
- if (shouldFileBeAnalyzed(child)) {
+ if (callbacks.shouldFileBeAnalyzed(child)) {
Source source = createSourceInContext(info.context, child);
changeSet.addedSource(source);
info.sources[path] = source;
@@ -437,18 +679,8 @@
}
}
- /**
- * Cancel all dependency subscriptions for the given context.
- */
- void _cancelDependencySubscriptions(_ContextInfo info) {
- for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) {
- s.cancel();
- }
- info.dependencySubscriptions.clear();
- }
-
void _checkForPackagespecUpdate(
- String path, _ContextInfo info, Folder folder) {
+ String path, ContextInfo info, Folder folder) {
// Check to see if this is the .packages file for this context and if so,
// update the context's source factory.
if (pathContext.basename(path) == PACKAGE_SPEC_NAME &&
@@ -457,22 +689,52 @@
if (packagespec.exists) {
Packages packages = _readPackagespec(packagespec);
if (packages != null) {
- updateContextPackageUriResolver(folder, null, packages);
+ callbacks.updateContextPackageUriResolver(
+ folder, new PackagesFileDisposition(packages));
}
}
}
}
/**
- * Compute the appropriate package URI resolver for [folder], and store
- * dependency information in [info]. Return `null` if no package map can
- * be computed.
+ * Compute the set of files that are being flushed, this is defined as
+ * the set of sources in the removed context (context.sources), that are
+ * orphaned by this context being removed (no other context includes this
+ * file.)
*/
- UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) {
- _cancelDependencySubscriptions(info);
- if (info.packageRoot != null) {
- info.packageMapInfo = null;
- JavaFile packagesDir = new JavaFile(info.packageRoot);
+ List<String> _computeFlushedFiles(ContextInfo info) {
+ AnalysisContext context = info.context;
+ HashSet<String> flushedFiles = new HashSet<String>();
+ for (Source source in context.sources) {
+ flushedFiles.add(source.fullName);
+ }
+ for (ContextInfo contextInfo in _rootInfo.descendants) {
+ AnalysisContext contextN = contextInfo.context;
+ if (context != contextN) {
+ for (Source source in contextN.sources) {
+ flushedFiles.remove(source.fullName);
+ }
+ }
+ }
+ return flushedFiles.toList(growable: false);
+ }
+
+ /**
+ * Compute the appropriate [FolderDisposition] for [folder]. Use
+ * [addDependency] to indicate which files needed to be consulted in order to
+ * figure out the [FolderDisposition]; these dependencies will be watched in
+ * order to determine when it is necessary to call this function again.
+ *
+ * TODO(paulberry): use [addDependency] for tracking all folder disposition
+ * dependencies (currently we only use it to track "pub list" dependencies).
+ */
+ FolderDisposition _computeFolderDisposition(
+ Folder folder, void addDependency(String path)) {
+ String packageRoot = normalizedPackageRoots[folder.path];
+ if (packageRoot != null) {
+ // TODO(paulberry): We shouldn't be using JavaFile here because it
+ // makes the code untestable (see dartbug.com/23909).
+ JavaFile packagesDir = new JavaFile(packageRoot);
Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>();
if (packagesDir.isDirectory()) {
for (JavaFile file in packagesDir.listFiles()) {
@@ -491,89 +753,66 @@
packageMap[file.getName()] = <Folder>[res];
}
}
- return new PackageMapUriResolver(resourceProvider, packageMap);
+ return new PackageMapDisposition(packageMap, packageRoot: packageRoot);
}
- //TODO(danrubel) remove this if it will never be called
- return new PackageUriResolver([packagesDir]);
+ // The package root does not exist (or is not a folder). Since
+ // [setRoots] ignores any package roots that don't exist (or aren't
+ // folders), the only way we should be able to get here is due to a race
+ // condition. In any case, the package root folder is gone, so we can't
+ // resolve packages.
+ return new NoPackageFolderDisposition(packageRoot: packageRoot);
} else {
- beginComputePackageMap();
+ callbacks.beginComputePackageMap();
if (packageResolverProvider != null) {
UriResolver resolver = packageResolverProvider(folder);
if (resolver != null) {
- return resolver;
+ return new CustomPackageResolverDisposition(resolver);
}
}
- OptimizingPubPackageMapInfo packageMapInfo;
+ PackageMapInfo packageMapInfo;
ServerPerformanceStatistics.pub.makeCurrentWhile(() {
- packageMapInfo =
- _packageMapProvider.computePackageMap(folder, info.packageMapInfo);
+ packageMapInfo = _packageMapProvider.computePackageMap(folder);
});
- endComputePackageMap();
+ callbacks.endComputePackageMap();
for (String dependencyPath in packageMapInfo.dependencies) {
- Resource resource = resourceProvider.getResource(dependencyPath);
- if (resource is File) {
- StreamSubscription<WatchEvent> subscription;
- subscription = resource.changes.listen((WatchEvent event) {
- if (info.packageMapInfo != null &&
- info.packageMapInfo.isChangedDependency(
- dependencyPath, resourceProvider)) {
- _recomputePackageUriResolver(info);
- }
- }, onError: (error, StackTrace stackTrace) {
- // Gracefully degrade if file is or becomes unwatchable
- _instrumentationService.logException(error, stackTrace);
- subscription.cancel();
- info.dependencySubscriptions.remove(subscription);
- });
- info.dependencySubscriptions.add(subscription);
- }
+ addDependency(dependencyPath);
}
- info.packageMapInfo = packageMapInfo;
if (packageMapInfo.packageMap == null) {
- return null;
+ return new NoPackageFolderDisposition();
}
- return new PackageMapUriResolver(
- resourceProvider, packageMapInfo.packageMap);
- // TODO(paulberry): if any of the dependencies is outside of [folder],
- // we'll need to watch their parent folders as well.
+ return new PackageMapDisposition(packageMapInfo.packageMap);
}
}
/**
- * Create a new empty context associated with [folder].
+ * Create a new empty context associated with [folder], having parent
+ * [parent] and using [packagespecFile] to resolve package URI's.
*/
- _ContextInfo _createContext(
- Folder folder, File packagespecFile, List<_ContextInfo> children) {
- _ContextInfo info = new _ContextInfo(
- folder, packagespecFile, children, normalizedPackageRoots[folder.path]);
- _contexts[folder] = info;
- var options = analysisOptionsProvider.getOptions(folder);
- processOptionsForContext(folder, options);
- info.changeSubscription = folder.changes.listen((WatchEvent event) {
- _handleWatchEvent(folder, info, event);
- });
- try {
- Packages packages;
- UriResolver packageUriResolver;
+ ContextInfo _createContext(
+ ContextInfo parent, Folder folder, File packagespecFile) {
+ ContextInfo info = new ContextInfo(this, parent, folder, packagespecFile,
+ normalizedPackageRoots[folder.path]);
+ Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder);
+ processOptionsForContext(info, options);
+ FolderDisposition disposition;
+ List<String> dependencies = <String>[];
- if (ENABLE_PACKAGESPEC_SUPPORT) {
- // Try .packages first.
- if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
- packages = _readPackagespec(packagespecFile);
- }
+ if (ENABLE_PACKAGESPEC_SUPPORT) {
+ // Try .packages first.
+ if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
+ Packages packages = _readPackagespec(packagespecFile);
+ disposition = new PackagesFileDisposition(packages);
}
-
- // Next resort to a package uri resolver.
- if (packages == null) {
- packageUriResolver = _computePackageUriResolver(folder, info);
- }
-
- info.context = addContext(folder, packageUriResolver, packages);
- info.context.name = folder.path;
- } catch (_) {
- info.changeSubscription.cancel();
- rethrow;
}
+
+ // Next resort to a package uri resolver.
+ if (disposition == null) {
+ disposition = _computeFolderDisposition(folder, dependencies.add);
+ }
+
+ info.setDependencies(dependencies);
+ info.context = callbacks.addContext(folder, disposition);
+ info.context.name = folder.path;
return info;
}
@@ -587,22 +826,12 @@
* If [withPackageSpecOnly] is `true`, a context will be created only if there
* is a 'pubspec.yaml' or '.packages' file in the [folder].
*
- * Returns created contexts.
+ * [parent] should be the parent of any contexts that are created.
*/
- List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) {
- // Try to find subfolders with pubspecs or .packages files.
- List<_ContextInfo> children = <_ContextInfo>[];
- try {
- for (Resource child in folder.getChildren()) {
- if (child is Folder) {
- children.addAll(_createContexts(child, true));
- }
- }
- } on FileSystemException {
- // The directory either doesn't exist or cannot be read. Either way, there
- // are no subfolders that need to be added.
- }
-
+ void _createContexts(
+ ContextInfo parent, Folder folder, bool withPackageSpecOnly) {
+ // Decide whether a context needs to be created for [folder] here, and if
+ // so, create it.
File packageSpec;
if (ENABLE_PACKAGESPEC_SUPPORT) {
@@ -615,53 +844,59 @@
packageSpec = folder.getChild(PUBSPEC_NAME);
}
- if (packageSpec.exists) {
- return <_ContextInfo>[
- _createContextWithSources(folder, packageSpec, children)
- ];
+ bool createContext = packageSpec.exists || !withPackageSpecOnly;
+ if (withPackageSpecOnly &&
+ packageSpec.exists &&
+ (parent != null) &&
+ parent.ignored(packageSpec.path)) {
+ // Don't create a context if the package spec is required and ignored.
+ createContext = false;
}
- // No packagespec? Done.
- if (withPackageSpecOnly) {
- return children;
+ if (createContext) {
+ parent = _createContext(parent, folder, packageSpec);
}
- // OK, create a context without a packagespec.
- return <_ContextInfo>[
- _createContextWithSources(folder, packageSpec, children)
- ];
- }
- /**
- * Create a new context associated with the given [folder]. The [pubspecFile]
- * is the `pubspec.yaml` file contained in the folder. Add any sources that
- * are not included in one of the [children] to the context.
- */
- _ContextInfo _createContextWithSources(
- Folder folder, File pubspecFile, List<_ContextInfo> children) {
- _ContextInfo info = _createContext(folder, pubspecFile, children);
- ChangeSet changeSet = new ChangeSet();
- _addSourceFiles(changeSet, folder, info);
- applyChangesToContext(folder, changeSet);
- return info;
+ // Try to find subfolders with pubspecs or .packages files.
+ try {
+ for (Resource child in folder.getChildren()) {
+ if (child is Folder) {
+ if (!parent.ignored(child.path)) {
+ _createContexts(parent, child, true);
+ }
+ }
+ }
+ } on FileSystemException {
+ // The directory either doesn't exist or cannot be read. Either way, there
+ // are no subfolders that need to be added.
+ }
+
+ if (createContext) {
+ // Now that the child contexts have been created, add the sources that
+ // don't belong to the children.
+ ChangeSet changeSet = new ChangeSet();
+ _addSourceFiles(changeSet, folder, parent);
+ callbacks.applyChangesToContext(folder, changeSet);
+ }
}
/**
* Clean up and destroy the context associated with the given folder.
*/
- void _destroyContext(Folder folder) {
- _ContextInfo info = _contexts[folder];
- info.changeSubscription.cancel();
- _cancelDependencySubscriptions(info);
- removeContext(folder);
- _contexts.remove(folder);
+ void _destroyContext(ContextInfo info) {
+ if (_changeSubscriptions.containsKey(info.folder)) {
+ _changeSubscriptions[info.folder].cancel();
+ }
+ callbacks.removeContext(info.folder, _computeFlushedFiles(info));
+ bool wasRemoved = info.parent.children.remove(info);
+ assert(wasRemoved);
}
/**
* Extract a new [packagespecFile]-based context from [oldInfo].
*/
- void _extractContext(_ContextInfo oldInfo, File packagespecFile) {
+ void _extractContext(ContextInfo oldInfo, File packagespecFile) {
Folder newFolder = packagespecFile.parent;
- _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []);
- newInfo.parent = oldInfo;
+ ContextInfo newInfo = _createContext(oldInfo, newFolder, packagespecFile);
// prepare sources to extract
Map<String, Source> extractedSources = new HashMap<String, Source>();
oldInfo.sources.forEach((path, source) {
@@ -676,7 +911,7 @@
newInfo.sources[path] = source;
changeSet.addedSource(source);
});
- applyChangesToContext(newFolder, changeSet);
+ callbacks.applyChangesToContext(newFolder, changeSet);
}
// update old context
{
@@ -685,18 +920,58 @@
oldInfo.sources.remove(path);
changeSet.removedSource(source);
});
- applyChangesToContext(oldInfo.folder, changeSet);
+ callbacks.applyChangesToContext(oldInfo.folder, changeSet);
+ }
+ // TODO(paulberry): every context that was previously a child of oldInfo is
+ // is still a child of oldInfo. This is wrong--some of them ought to be
+ // adopted by newInfo now.
+ }
+
+ /**
+ * Return the [ContextInfo] for the "innermost" context whose associated
+ * folder is or contains the given path. ("innermost" refers to the nesting
+ * of contexts, so if there is a context for path /foo and a context for
+ * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is
+ * the context for /foo/bar.)
+ *
+ * If no context contains the given path, `null` is returned.
+ */
+ ContextInfo _getInnermostContextInfoFor(String path) {
+ ContextInfo info = _rootInfo.findChildInfoFor(path);
+ if (info == null) {
+ return null;
+ }
+ while (true) {
+ ContextInfo childInfo = info.findChildInfoFor(path);
+ if (childInfo == null) {
+ return info;
+ }
+ info = childInfo;
}
}
- void _handleWatchEvent(Folder folder, _ContextInfo info, WatchEvent event) {
+ void _handleWatchEvent(WatchEvent event) {
+ // Figure out which context this event applies to.
// TODO(brianwilkerson) If a file is explicitly included in one context
// but implicitly referenced in another context, we will only send a
// changeSet to the context that explicitly includes the file (because
// that's the only context that's watching the file).
+ ContextInfo info = _getInnermostContextInfoFor(event.path);
+ if (info == null) {
+ // This event doesn't apply to any context. This could happen due to a
+ // race condition (e.g. a context was removed while one of its events was
+ // in the event loop). The event is inapplicable now, so just ignore it.
+ return;
+ }
_instrumentationService.logWatchEvent(
- folder.path, event.path, event.type.toString());
+ info.folder.path, event.path, event.type.toString());
String path = event.path;
+ // First handle changes that affect folderDisposition (since these need to
+ // be processed regardless of whether they are part of an excluded/ignored
+ // path).
+ if (info.hasDependency(path)) {
+ _recomputeFolderDisposition(info);
+ }
// maybe excluded globally
if (_isExcluded(path)) {
return;
@@ -711,7 +986,7 @@
// handle the change
switch (event.type) {
case ChangeType.ADD:
- if (_isInPackagesDir(path, folder)) {
+ if (_isInPackagesDir(path, info.folder)) {
return;
}
@@ -721,7 +996,7 @@
String directoryPath = pathContext.dirname(path);
// Check to see if we need to create a new context.
- if (info.isRoot) {
+ if (info.isTopLevel) {
// Only create a new context if this is not the same directory
// described by our info object.
@@ -747,7 +1022,7 @@
} else {
// pubspec was added in a sub-folder, extract a new context
if (_isPubspec(path) &&
- info.isRoot &&
+ info.isTopLevel &&
!info.isPathToPackageDescription(path)) {
_extractContext(info, resource);
return;
@@ -759,11 +1034,11 @@
// that case don't add it.
if (resource is File) {
File file = resource;
- if (shouldFileBeAnalyzed(file)) {
+ if (callbacks.shouldFileBeAnalyzed(file)) {
ChangeSet changeSet = new ChangeSet();
Source source = createSourceInContext(info.context, file);
changeSet.addedSource(source);
- applyChangesToContext(folder, changeSet);
+ callbacks.applyChangesToContext(info.folder, changeSet);
info.sources[path] = source;
}
}
@@ -773,7 +1048,7 @@
// If package spec info is removed, check to see if we can merge contexts.
// Note that it's important to verify that there is NEITHER a .packages nor a
// lingering pubspec.yaml before merging.
- if (!info.isRoot) {
+ if (!info.isTopLevel) {
if (ENABLE_PACKAGESPEC_SUPPORT) {
String directoryPath = pathContext.dirname(path);
@@ -810,7 +1085,7 @@
sources.forEach((Source source) {
changeSet.removedSource(source);
});
- applyChangesToContext(folder, changeSet);
+ callbacks.applyChangesToContext(info.folder, changeSet);
info.sources.remove(path);
}
break;
@@ -821,18 +1096,13 @@
sources.forEach((Source source) {
changeSet.changedSource(source);
});
- applyChangesToContext(folder, changeSet);
+ callbacks.applyChangesToContext(info.folder, changeSet);
}
break;
}
//TODO(pquitslund): find the right place for this
- _checkForPackagespecUpdate(path, info, folder);
-
- if (info.packageMapInfo != null &&
- info.packageMapInfo.isChangedDependency(path, resourceProvider)) {
- _recomputePackageUriResolver(info);
- }
+ _checkForPackagespecUpdate(path, info, info.folder);
}
/**
@@ -870,11 +1140,11 @@
/**
* Merges [info] context into its parent.
*/
- void _mergeContext(_ContextInfo info) {
+ void _mergeContext(ContextInfo info) {
// destroy the context
- _destroyContext(info.folder);
+ _destroyContext(info);
// add files to the parent context
- _ContextInfo parentInfo = info.parent;
+ ContextInfo parentInfo = info.parent;
if (parentInfo != null) {
parentInfo.children.remove(info);
ChangeSet changeSet = new ChangeSet();
@@ -882,7 +1152,7 @@
parentInfo.sources[path] = source;
changeSet.addedSource(source);
});
- applyChangesToContext(parentInfo.folder, changeSet);
+ callbacks.applyChangesToContext(parentInfo.folder, changeSet);
}
}
@@ -899,17 +1169,19 @@
}
/**
- * Recompute the package URI resolver for the context described by [info],
+ * Recompute the [FolderDisposition] for the context described by [info],
* and update the client appropriately.
*/
- void _recomputePackageUriResolver(_ContextInfo info) {
+ void _recomputeFolderDisposition(ContextInfo info) {
// TODO(paulberry): when computePackageMap is changed into an
// asynchronous API call, we'll want to suspend analysis for this context
// while we're rerunning "pub list", since any analysis we complete while
// "pub list" is in progress is just going to get thrown away anyhow.
- UriResolver packageUriResolver =
- _computePackageUriResolver(info.folder, info);
- updateContextPackageUriResolver(info.folder, packageUriResolver, null);
+ List<String> dependencies = <String>[];
+ FolderDisposition disposition =
+ _computeFolderDisposition(info.folder, dependencies.add);
+ info.setDependencies(dependencies);
+ callbacks.updateContextPackageUriResolver(info.folder, disposition);
}
/**
@@ -929,73 +1201,6 @@
}
/**
- * Class that maintains a mapping from included/excluded paths to a set of
- * folders that should correspond to analysis contexts.
- */
-abstract class ContextManager {
- // TODO(brianwilkerson) Support:
- // setting the default analysis options
- // setting the default content cache
- // setting the default SDK
- // maintaining AnalysisContext.folderMap (or remove it)
- // telling server when a context has been added or removed (see onContextsChanged)
- // telling server when a context needs to be re-analyzed
- // notifying the client when results should be flushed
- // using analyzeFileFunctions to determine which files to analyze
- //
- // TODO(brianwilkerson) Move this class to a public library.
-
-// /**
-// * The default options used to create new analysis contexts.
-// */
-// AnalysisOptionsImpl get defaultOptions;
-
- /**
- * Return the list of excluded paths (folders and files) most recently passed
- * to [setRoots].
- */
- List<String> get excludedPaths;
-
- /**
- * Return the list of included paths (folders and files) most recently passed
- * to [setRoots].
- */
- List<String> get includedPaths;
-
-// /**
-// * A stream that is notified when contexts are added or removed.
-// */
-// Stream<ContextsChangedEvent> get onContextsChanged;
-
- /**
- * Return a list containing all of the contexts contained in the given
- * [analysisRoot].
- */
- List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot);
-
- /**
- * Return `true` if the given absolute [path] is in one of the current
- * root folders and is not excluded.
- */
- bool isInAnalysisRoot(String path);
-
- /**
- * Rebuild the set of contexts from scratch based on the data last sent to
- * [setRoots]. Only contexts contained in the given list of analysis [roots]
- * will be rebuilt, unless the list is `null`, in which case every context
- * will be rebuilt.
- */
- void refresh(List<Resource> roots);
-
- /**
- * Change the set of paths which should be used as starting points to
- * determine the context directories.
- */
- void setRoots(List<String> includedPaths, List<String> excludedPaths,
- Map<String, String> packageRoots);
-}
-
-/**
* An indication that one or more contexts were added, changed, or removed.
*
* The lists of [added], [changed] and [removed] contexts will not contain
@@ -1028,104 +1233,121 @@
}
/**
- * Information tracked by the [ContextManager] for each context.
+ * Concrete [FolderDisposition] object indicating that the context for a given
+ * folder should resolve package URIs using a custom URI resolver.
*/
-class _ContextInfo {
+class CustomPackageResolverDisposition extends FolderDisposition {
/**
- * The [Folder] for which this information object is created.
+ * The [UriResolver] that should be used to resolve package URIs.
*/
- final Folder folder;
+ UriResolver resolver;
- /// The [PathFilter] used to filter sources from being analyzed.
- final PathFilter pathFilter;
+ CustomPackageResolverDisposition(this.resolver);
+
+ @override
+ String get packageRoot => null;
+
+ @override
+ Packages get packages => null;
+
+ @override
+ Iterable<UriResolver> createPackageUriResolvers(
+ ResourceProvider resourceProvider) => <UriResolver>[resolver];
+}
+
+/**
+ * An instance of the class [FolderDisposition] represents the information
+ * gathered by the [ContextManagerImpl] to determine how to create an
+ * [AnalysisContext] for a given folder.
+ *
+ * Note: [ContextManagerImpl] may use equality testing and hash codes to
+ * determine when two folders should share the same context, so derived classes
+ * may need to override operator== and hashCode() if object identity is
+ * insufficient.
+ *
+ * TODO(paulberry): consider adding a flag to indicate that it is not necessary
+ * to recurse into the given folder looking for additional contexts to create
+ * or files to analyze (this could help avoid unnecessarily weighing down the
+ * system with file watchers).
+ */
+abstract class FolderDisposition {
+ /**
+ * If this [FolderDisposition] was created based on a package root
+ * folder, the absolute path to that folder. Otherwise `null`.
+ */
+ String get packageRoot;
/**
- * The enclosed pubspec-based contexts.
+ * If contexts governed by this [FolderDisposition] should resolve packages
+ * using the ".packages" file mechanism (DEP 5), retrieve the [Packages]
+ * object that resulted from parsing the ".packages" file.
*/
- final List<_ContextInfo> children;
+ Packages get packages;
/**
- * The package root for this context, or null if there is no package root.
+ * Create all the [UriResolver]s which should be used to resolve packages in
+ * contexts governed by this [FolderDisposition].
+ *
+ * [resourceProvider] is provided since it is needed to construct most
+ * [UriResolver]s.
*/
- String packageRoot;
+ Iterable<UriResolver> createPackageUriResolvers(
+ ResourceProvider resourceProvider);
+}
- /**
- * The [_ContextInfo] that encloses this one.
- */
- _ContextInfo parent;
+/**
+ * Concrete [FolderDisposition] object indicating that the context for a given
+ * folder should not resolve "package:" URIs at all.
+ */
+class NoPackageFolderDisposition extends FolderDisposition {
+ @override
+ final String packageRoot;
- /**
- * The package description file path for this context.
- */
- String packageDescriptionPath;
+ NoPackageFolderDisposition({this.packageRoot});
- /**
- * Stream subscription we are using to watch the context's directory for
- * changes.
- */
- StreamSubscription<WatchEvent> changeSubscription;
+ @override
+ Packages get packages => null;
- /**
- * Stream subscriptions we are using to watch the files
- * used to determine the package map.
- */
- final List<StreamSubscription<WatchEvent>> dependencySubscriptions =
- <StreamSubscription<WatchEvent>>[];
+ @override
+ Iterable<UriResolver> createPackageUriResolvers(
+ ResourceProvider resourceProvider) => const <UriResolver>[];
+}
- /**
- * The analysis context that was created for the [folder].
- */
- AnalysisContext context;
+/**
+ * Concrete [FolderDisposition] object indicating that the context for a given
+ * folder should resolve packages using a package map.
+ */
+class PackageMapDisposition extends FolderDisposition {
+ final Map<String, List<Folder>> packageMap;
- /**
- * Map from full path to the [Source] object, for each source that has been
- * added to the context.
- */
- Map<String, Source> sources = new HashMap<String, Source>();
+ @override
+ final String packageRoot;
- /**
- * Info returned by the last call to
- * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the
- * package map hasn't been computed for this context yet.
- */
- OptimizingPubPackageMapInfo packageMapInfo;
+ PackageMapDisposition(this.packageMap, {this.packageRoot});
- _ContextInfo(
- Folder folder, File packagespecFile, this.children, this.packageRoot)
- : folder = folder,
- pathFilter = new PathFilter(folder.path, null) {
- packageDescriptionPath = packagespecFile.path;
- for (_ContextInfo child in children) {
- child.parent = this;
- }
- }
+ @override
+ Packages get packages => null;
- /**
- * Returns `true` if this context is root folder based.
- */
- bool get isRoot => parent == null;
+ @override
+ Iterable<UriResolver> createPackageUriResolvers(
+ ResourceProvider resourceProvider) =>
+ <UriResolver>[new PackageMapUriResolver(resourceProvider, packageMap)];
+}
- /**
- * Returns `true` if [path] is excluded, as it is in one of the children.
- */
- bool excludes(String path) {
- return children.any((child) {
- return child.folder.contains(path);
- });
- }
+/**
+ * Concrete [FolderDisposition] object indicating that the context for a given
+ * folder should resolve packages using a ".packages" file.
+ */
+class PackagesFileDisposition extends FolderDisposition {
+ @override
+ final Packages packages;
- /**
- * Returns `true` if [resource] is excluded, as it is in one of the children.
- */
- bool excludesResource(Resource resource) => excludes(resource.path);
+ PackagesFileDisposition(this.packages) {}
- /// Returns `true` if [path] should be ignored.
- bool ignored(String path) => pathFilter.ignored(path);
+ @override
+ String get packageRoot => null;
- /**
- * Returns `true` if [path] is the package description file for this context
- * (pubspec.yaml or .packages).
- */
- bool isPathToPackageDescription(String path) =>
- path == packageDescriptionPath;
+ @override
+ Iterable<UriResolver> createPackageUriResolvers(
+ ResourceProvider resourceProvider) => const <UriResolver>[];
}
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 42afae3..483f532 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -112,13 +112,12 @@
Response getNavigation(Request request) {
var params = new AnalysisGetNavigationParams.fromRequest(request);
String file = params.file;
- int offset = params.offset;
- Future<AnalysisDoneReason> completionFuture =
+ Future<AnalysisDoneReason> analysisFuture =
server.onFileAnalysisComplete(file);
- if (completionFuture == null) {
+ if (analysisFuture == null) {
return new Response.getNavigationInvalidFile(request);
}
- completionFuture.then((AnalysisDoneReason reason) {
+ analysisFuture.then((AnalysisDoneReason reason) {
switch (reason) {
case AnalysisDoneReason.COMPLETE:
List<CompilationUnit> units =
@@ -128,11 +127,10 @@
} else {
DartUnitNavigationComputer computer =
new DartUnitNavigationComputer();
+ _GetNavigationAstVisitor visitor = new _GetNavigationAstVisitor(
+ params.offset, params.offset + params.length, computer);
for (CompilationUnit unit in units) {
- AstNode node = new NodeLocator(offset).searchWithin(unit);
- if (node != null) {
- computer.compute(node);
- }
+ unit.accept(visitor);
}
server.sendResponse(new AnalysisGetNavigationResult(
computer.files, computer.targets, computer.regions)
@@ -268,11 +266,6 @@
var params = new AnalysisUpdateOptionsParams.fromRequest(request);
AnalysisOptions newOptions = params.options;
List<OptionUpdater> updaters = new List<OptionUpdater>();
- if (newOptions.enableNullAwareOperators != null) {
- updaters.add((engine.AnalysisOptionsImpl options) {
- options.enableNullAwareOperators = newOptions.enableNullAwareOperators;
- });
- }
if (newOptions.generateDart2jsHints != null) {
updaters.add((engine.AnalysisOptionsImpl options) {
options.dart2jsHint = newOptions.generateDart2jsHints;
@@ -292,3 +285,36 @@
return new AnalysisUpdateOptionsResult().toResponse(request.id);
}
}
+
+/**
+ * An AST visitor that computer navigation regions in the givne region.
+ */
+class _GetNavigationAstVisitor extends UnifyingAstVisitor {
+ final int rangeStart;
+ final int rangeEnd;
+ final DartUnitNavigationComputer computer;
+
+ _GetNavigationAstVisitor(this.rangeStart, this.rangeEnd, this.computer);
+
+ bool isInRange(int offset) {
+ return rangeStart <= offset && offset <= rangeEnd;
+ }
+
+ @override
+ visitNode(AstNode node) {
+ // The node ends before the range starts.
+ if (node.end < rangeStart) {
+ return;
+ }
+ // The node starts after the range ends.
+ if (node.offset > rangeEnd) {
+ return;
+ }
+ // The node starts or ends in the range.
+ if (isInRange(node.offset) || isInRange(node.end)) {
+ computer.compute(node);
+ return;
+ }
+ super.visitNode(node);
+ }
+}
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index ee26dd8..3213537 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -14,6 +14,7 @@
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/correction/organize_directives.dart';
import 'package:analysis_server/src/services/correction/sort_members.dart';
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
@@ -156,8 +157,8 @@
for (engine.AnalysisError error in errorInfo.errors) {
int errorLine = lineInfo.getLocation(error.offset).lineNumber;
if (errorLine == requestLine) {
- List<Fix> fixes =
- computeFixes(server.serverPlugin, unit.element.context, error);
+ List<Fix> fixes = computeFixes(server.serverPlugin,
+ server.resourceProvider, unit.element.context, error);
if (fixes.isNotEmpty) {
AnalysisError serverError =
newAnalysisError_fromEngine(lineInfo, error);
@@ -190,6 +191,8 @@
return getFixes(request);
} else if (requestName == EDIT_GET_REFACTORING) {
return _getRefactoring(request);
+ } else if (requestName == EDIT_ORGANIZE_DIRECTIVES) {
+ return organizeDirectives(request);
} else if (requestName == EDIT_SORT_MEMBERS) {
return sortMembers(request);
}
@@ -199,6 +202,38 @@
return null;
}
+ Response organizeDirectives(Request request) {
+ var params = new EditOrganizeDirectivesParams.fromRequest(request);
+ // prepare file
+ String file = params.file;
+ if (!engine.AnalysisEngine.isDartFileName(file)) {
+ return new Response.fileNotAnalyzed(request, file);
+ }
+ // prepare resolved units
+ List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
+ if (units.isEmpty) {
+ return new Response.fileNotAnalyzed(request, file);
+ }
+ // prepare context
+ CompilationUnit unit = units.first;
+ engine.AnalysisContext context = unit.element.context;
+ Source source = unit.element.source;
+ List<engine.AnalysisError> errors = context.computeErrors(source);
+ // check if there are scan/parse errors in the file
+ int numScanParseErrors = _getNumberOfScanParseErrors(errors);
+ if (numScanParseErrors != 0) {
+ return new Response.organizeDirectivesError(
+ request, 'File has $numScanParseErrors scan/parse errors.');
+ }
+ // do organize
+ int fileStamp = context.getModificationStamp(source);
+ String code = context.getContents(source).data;
+ DirectiveOrganizer sorter = new DirectiveOrganizer(code, unit, errors);
+ List<SourceEdit> edits = sorter.organize();
+ SourceFileEdit fileEdit = new SourceFileEdit(file, fileStamp, edits: edits);
+ return new EditOrganizeDirectivesResult(fileEdit).toResponse(request.id);
+ }
+
Response sortMembers(Request request) {
var params = new EditSortMembersParams.fromRequest(request);
// prepare file
@@ -215,15 +250,9 @@
CompilationUnit unit = units.first;
engine.AnalysisContext context = unit.element.context;
Source source = unit.element.source;
- // check if there are no scan/parse errors in the file
+ // check if there are scan/parse errors in the file
engine.AnalysisErrorInfo errors = context.getErrors(source);
- int numScanParseErrors = 0;
- errors.errors.forEach((engine.AnalysisError error) {
- if (error.errorCode is engine.ScannerErrorCode ||
- error.errorCode is engine.ParserErrorCode) {
- numScanParseErrors++;
- }
- });
+ int numScanParseErrors = _getNumberOfScanParseErrors(errors.errors);
if (numScanParseErrors != 0) {
return new Response.sortMembersParseErrors(request, numScanParseErrors);
}
@@ -304,6 +333,17 @@
void _newRefactoringManager() {
refactoringManager = new _RefactoringManager(server, searchEngine);
}
+
+ static int _getNumberOfScanParseErrors(List<engine.AnalysisError> errors) {
+ int numScanParseErrors = 0;
+ for (engine.AnalysisError error in errors) {
+ if (error.errorCode is engine.ScannerErrorCode ||
+ error.errorCode is engine.ParserErrorCode) {
+ numScanParseErrors++;
+ }
+ }
+ return numScanParseErrors;
+ }
}
/**
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index 5ecfe20..f92288f 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -6166,6 +6166,164 @@
}
/**
+ * edit.organizeDirectives params
+ *
+ * {
+ * "file": FilePath
+ * }
+ */
+class EditOrganizeDirectivesParams implements HasToJson {
+ String _file;
+
+ /**
+ * The Dart file to organize directives in.
+ */
+ String get file => _file;
+
+ /**
+ * The Dart file to organize directives in.
+ */
+ void set file(String value) {
+ assert(value != null);
+ this._file = value;
+ }
+
+ EditOrganizeDirectivesParams(String file) {
+ this.file = file;
+ }
+
+ factory EditOrganizeDirectivesParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ String file;
+ if (json.containsKey("file")) {
+ file = jsonDecoder._decodeString(jsonPath + ".file", json["file"]);
+ } else {
+ throw jsonDecoder.missingKey(jsonPath, "file");
+ }
+ return new EditOrganizeDirectivesParams(file);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "edit.organizeDirectives params", json);
+ }
+ }
+
+ factory EditOrganizeDirectivesParams.fromRequest(Request request) {
+ return new EditOrganizeDirectivesParams.fromJson(
+ new RequestDecoder(request), "params", request._params);
+ }
+
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["file"] = file;
+ return result;
+ }
+
+ Request toRequest(String id) {
+ return new Request(id, "edit.organizeDirectives", toJson());
+ }
+
+ @override
+ String toString() => JSON.encode(toJson());
+
+ @override
+ bool operator==(other) {
+ if (other is EditOrganizeDirectivesParams) {
+ return file == other.file;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = _JenkinsSmiHash.combine(hash, file.hashCode);
+ return _JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
+ * edit.organizeDirectives result
+ *
+ * {
+ * "edit": SourceFileEdit
+ * }
+ */
+class EditOrganizeDirectivesResult implements HasToJson {
+ SourceFileEdit _edit;
+
+ /**
+ * The file edit that is to be applied to the given file to effect the
+ * organizing.
+ */
+ SourceFileEdit get edit => _edit;
+
+ /**
+ * The file edit that is to be applied to the given file to effect the
+ * organizing.
+ */
+ void set edit(SourceFileEdit value) {
+ assert(value != null);
+ this._edit = value;
+ }
+
+ EditOrganizeDirectivesResult(SourceFileEdit edit) {
+ this.edit = edit;
+ }
+
+ factory EditOrganizeDirectivesResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ SourceFileEdit edit;
+ if (json.containsKey("edit")) {
+ edit = new SourceFileEdit.fromJson(jsonDecoder, jsonPath + ".edit", json["edit"]);
+ } else {
+ throw jsonDecoder.missingKey(jsonPath, "edit");
+ }
+ return new EditOrganizeDirectivesResult(edit);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "edit.organizeDirectives result", json);
+ }
+ }
+
+ factory EditOrganizeDirectivesResult.fromResponse(Response response) {
+ return new EditOrganizeDirectivesResult.fromJson(
+ new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response._result);
+ }
+
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["edit"] = edit.toJson();
+ return result;
+ }
+
+ Response toResponse(String id) {
+ return new Response(id, result: toJson());
+ }
+
+ @override
+ String toString() => JSON.encode(toJson());
+
+ @override
+ bool operator==(other) {
+ if (other is EditOrganizeDirectivesResult) {
+ return edit == other.edit;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = _JenkinsSmiHash.combine(hash, edit.hashCode);
+ return _JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
* execution.createContext params
*
* {
@@ -7403,14 +7561,14 @@
bool _generateLints;
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed async feature.
*/
bool get enableAsync => _enableAsync;
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed async feature.
*/
@@ -7419,7 +7577,7 @@
}
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed deferred
* loading feature.
@@ -7427,7 +7585,7 @@
bool get enableDeferredLoading => _enableDeferredLoading;
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed deferred
* loading feature.
@@ -7437,14 +7595,14 @@
}
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed enum feature.
*/
bool get enableEnums => _enableEnums;
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed enum feature.
*/
@@ -7453,12 +7611,16 @@
}
/**
+ * Deprecated: this feature is always enabled.
+ *
* True if the client wants to enable support for the proposed "null aware
* operators" feature.
*/
bool get enableNullAwareOperators => _enableNullAwareOperators;
/**
+ * Deprecated: this feature is always enabled.
+ *
* True if the client wants to enable support for the proposed "null aware
* operators" feature.
*/
@@ -12665,6 +12827,7 @@
*
* enum {
* CONTENT_MODIFIED
+ * FILE_NOT_ANALYZED
* FORMAT_INVALID_FILE
* FORMAT_WITH_ERRORS
* GET_ERRORS_INVALID_FILE
@@ -12675,6 +12838,7 @@
* INVALID_PARAMETER
* INVALID_REQUEST
* NO_INDEX_GENERATED
+ * ORGANIZE_DIRECTIVES_ERROR
* REFACTORING_REQUEST_CANCELLED
* SERVER_ALREADY_STARTED
* SERVER_ERROR
@@ -12695,6 +12859,12 @@
static const CONTENT_MODIFIED = const RequestErrorCode._("CONTENT_MODIFIED");
/**
+ * A request specified a FilePath which does not match a file in an analysis
+ * root, or the requested operation is not available for the file.
+ */
+ static const FILE_NOT_ANALYZED = const RequestErrorCode._("FILE_NOT_ANALYZED");
+
+ /**
* An "edit.format" request specified a FilePath which does not match a Dart
* file in an analysis root.
*/
@@ -12712,8 +12882,8 @@
static const GET_ERRORS_INVALID_FILE = const RequestErrorCode._("GET_ERRORS_INVALID_FILE");
/**
- * An "analysis.getErrors" request specified a FilePath which does not match
- * a file currently subject to analysis.
+ * An "analysis.getNavigation" request specified a FilePath which does not
+ * match a file currently subject to analysis.
*/
static const GET_NAVIGATION_INVALID_FILE = const RequestErrorCode._("GET_NAVIGATION_INVALID_FILE");
@@ -12752,6 +12922,12 @@
static const NO_INDEX_GENERATED = const RequestErrorCode._("NO_INDEX_GENERATED");
/**
+ * An "edit.organizeDirectives" request specified a Dart file that cannot be
+ * analyzed. The reason is described in the message.
+ */
+ static const ORGANIZE_DIRECTIVES_ERROR = const RequestErrorCode._("ORGANIZE_DIRECTIVES_ERROR");
+
+ /**
* Another refactoring request was received during processing of this one.
*/
static const REFACTORING_REQUEST_CANCELLED = const RequestErrorCode._("REFACTORING_REQUEST_CANCELLED");
@@ -12817,7 +12993,7 @@
/**
* A list containing all of the enum values that are defined.
*/
- static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
+ static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
final String name;
@@ -12827,6 +13003,8 @@
switch (name) {
case "CONTENT_MODIFIED":
return CONTENT_MODIFIED;
+ case "FILE_NOT_ANALYZED":
+ return FILE_NOT_ANALYZED;
case "FORMAT_INVALID_FILE":
return FORMAT_INVALID_FILE;
case "FORMAT_WITH_ERRORS":
@@ -12847,6 +13025,8 @@
return INVALID_REQUEST;
case "NO_INDEX_GENERATED":
return NO_INDEX_GENERATED;
+ case "ORGANIZE_DIRECTIVES_ERROR":
+ return ORGANIZE_DIRECTIVES_ERROR;
case "REFACTORING_REQUEST_CANCELLED":
return REFACTORING_REQUEST_CANCELLED;
case "SERVER_ALREADY_STARTED":
diff --git a/pkg/analysis_server/lib/src/get_handler.dart b/pkg/analysis_server/lib/src/get_handler.dart
index 7068b9d..360b5da 100644
--- a/pkg/analysis_server/lib/src/get_handler.dart
+++ b/pkg/analysis_server/lib/src/get_handler.dart
@@ -1010,7 +1010,7 @@
List<Folder> folders = folderMap.keys.toList();
folders.sort((Folder first, Folder second) =>
first.shortName.compareTo(second.shortName));
- AnalysisOptionsImpl options = analysisServer.contextManager.defaultOptions;
+ AnalysisOptionsImpl options = analysisServer.defaultContextOptions;
ServerOperationQueue operationQueue = analysisServer.operationQueue;
buffer.write('<h3>Analysis Domain</h3>');
@@ -1052,8 +1052,6 @@
_writeOption(
buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
_writeOption(buffer, 'Cache size', options.cacheSize);
- _writeOption(buffer, 'Enable null-aware operators',
- options.enableNullAwareOperators);
_writeOption(
buffer, 'Enable strict call checks', options.enableStrictCallChecks);
_writeOption(buffer, 'Generate hints', options.hint);
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index aec8d71..ef960f0 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -392,7 +392,8 @@
var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]';
String disambiguator = _decodeString(disambiguatorPath, json[field]);
if (!decoders.containsKey(disambiguator)) {
- throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}', json);
+ throw mismatch(
+ disambiguatorPath, 'One of: ${decoders.keys.toList()}', json);
}
return decoders[disambiguator](jsonPath, json);
} else {
@@ -625,8 +626,8 @@
buffer.write(JSON.encode(actual));
buffer.write('"');
}
- return new RequestFailure(new Response.invalidParameter(
- _request, jsonPath, buffer.toString()));
+ return new RequestFailure(
+ new Response.invalidParameter(_request, jsonPath, buffer.toString()));
}
@override
@@ -721,20 +722,31 @@
: _result = result;
/**
+ * Initialize a newly created instance to represent the
+ * FILE_NOT_ANALYZED error condition.
+ */
+ Response.fileNotAnalyzed(Request request, String file)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.FILE_NOT_ANALYZED,
+ 'File is not analyzed: $file.'));
+
+ /**
* Initialize a newly created instance to represent the FORMAT_INVALID_FILE
* error condition.
*/
- Response.formatInvalidFile(Request request) : this(request.id,
- error: new RequestError(RequestErrorCode.FORMAT_INVALID_FILE,
- 'Error during `edit.format`: invalid file.'));
+ Response.formatInvalidFile(Request request)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.FORMAT_INVALID_FILE,
+ 'Error during `edit.format`: invalid file.'));
/**
* Initialize a newly created instance to represent the FORMAT_WITH_ERROR
* error condition.
*/
- Response.formatWithErrors(Request request) : this(request.id,
- error: new RequestError(RequestErrorCode.FORMAT_WITH_ERRORS,
- 'Error during `edit.format`: source contains syntax errors.'));
+ Response.formatWithErrors(Request request)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.FORMAT_WITH_ERRORS,
+ 'Error during `edit.format`: source contains syntax errors.'));
/**
* Initialize a newly created instance based upon the given JSON data
@@ -766,37 +778,40 @@
* Initialize a newly created instance to represent the
* GET_ERRORS_INVALID_FILE error condition.
*/
- Response.getErrorsInvalidFile(Request request) : this(request.id,
- error: new RequestError(RequestErrorCode.GET_ERRORS_INVALID_FILE,
- 'Error during `analysis.getErrors`: invalid file.'));
+ Response.getErrorsInvalidFile(Request request)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.GET_ERRORS_INVALID_FILE,
+ 'Error during `analysis.getErrors`: invalid file.'));
/**
* Initialize a newly created instance to represent the
* GET_NAVIGATION_INVALID_FILE error condition.
*/
- Response.getNavigationInvalidFile(Request request) : this(request.id,
- error: new RequestError(RequestErrorCode.GET_NAVIGATION_INVALID_FILE,
- 'Error during `analysis.getNavigation`: invalid file.'));
+ Response.getNavigationInvalidFile(Request request)
+ : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.GET_NAVIGATION_INVALID_FILE,
+ 'Error during `analysis.getNavigation`: invalid file.'));
/**
* Initialize a newly created instance to represent an error condition caused
* by an analysis.reanalyze [request] that specifies an analysis root that is
* not in the current list of analysis roots.
*/
- Response.invalidAnalysisRoot(Request request, String rootPath) : this(
- request.id,
- error: new RequestError(RequestErrorCode.INVALID_ANALYSIS_ROOT,
- "Invalid analysis root: $rootPath"));
+ Response.invalidAnalysisRoot(Request request, String rootPath)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.INVALID_ANALYSIS_ROOT,
+ "Invalid analysis root: $rootPath"));
/**
* Initialize a newly created instance to represent an error condition caused
* by a [request] that specifies an execution context whose context root does
* not exist.
*/
- Response.invalidExecutionContext(Request request, String contextId) : this(
- request.id,
- error: new RequestError(RequestErrorCode.INVALID_EXECUTION_CONTEXT,
- "Invalid execution context: $contextId"));
+ Response.invalidExecutionContext(Request request, String contextId)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.INVALID_EXECUTION_CONTEXT,
+ "Invalid execution context: $contextId"));
/**
* Initialize a newly created instance to represent an error condition caused
@@ -807,33 +822,45 @@
*/
Response.invalidParameter(Request request, String path, String expectation)
: this(request.id,
- error: new RequestError(RequestErrorCode.INVALID_PARAMETER,
- "Invalid parameter '$path'. $expectation."));
+ error: new RequestError(RequestErrorCode.INVALID_PARAMETER,
+ "Invalid parameter '$path'. $expectation."));
/**
* Initialize a newly created instance to represent an error condition caused
* by a malformed request.
*/
- Response.invalidRequestFormat() : this('',
- error: new RequestError(
- RequestErrorCode.INVALID_REQUEST, 'Invalid request'));
+ Response.invalidRequestFormat()
+ : this('',
+ error: new RequestError(
+ RequestErrorCode.INVALID_REQUEST, 'Invalid request'));
/**
* Initialize a newly created instance to represent an error condition caused
* by a request that requires an index, but indexing is disabled.
*/
- Response.noIndexGenerated(Request request) : this(request.id,
- error: new RequestError(
- RequestErrorCode.NO_INDEX_GENERATED, 'Indexing is disabled'));
+ Response.noIndexGenerated(Request request)
+ : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.NO_INDEX_GENERATED, 'Indexing is disabled'));
+
+ /**
+ * Initialize a newly created instance to represent the
+ * ORGANIZE_DIRECTIVES_ERROR error condition.
+ */
+ Response.organizeDirectivesError(Request request, String message)
+ : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.ORGANIZE_DIRECTIVES_ERROR, message));
/**
* Initialize a newly created instance to represent the
* REFACTORING_REQUEST_CANCELLED error condition.
*/
- Response.refactoringRequestCancelled(Request request) : this(request.id,
- error: new RequestError(
- RequestErrorCode.REFACTORING_REQUEST_CANCELLED,
- 'The `edit.getRefactoring` request was cancelled.'));
+ Response.refactoringRequestCancelled(Request request)
+ : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.REFACTORING_REQUEST_CANCELLED,
+ 'The `edit.getRefactoring` request was cancelled.'));
/**
* Initialize a newly created instance to represent the SERVER_ERROR error
@@ -852,49 +879,52 @@
* Initialize a newly created instance to represent the
* SORT_MEMBERS_INVALID_FILE error condition.
*/
- Response.sortMembersInvalidFile(Request request) : this(request.id,
- error: new RequestError(RequestErrorCode.SORT_MEMBERS_INVALID_FILE,
- 'Error during `edit.sortMembers`: invalid file.'));
+ Response.sortMembersInvalidFile(Request request)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.SORT_MEMBERS_INVALID_FILE,
+ 'Error during `edit.sortMembers`: invalid file.'));
/**
* Initialize a newly created instance to represent the
* SORT_MEMBERS_PARSE_ERRORS error condition.
*/
- Response.sortMembersParseErrors(Request request, int numErrors) : this(
- request.id,
- error: new RequestError(RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS,
- 'Error during `edit.sortMembers`: file has $numErrors scan/parse errors.'));
+ Response.sortMembersParseErrors(Request request, int numErrors)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS,
+ 'Error during `edit.sortMembers`: file has $numErrors scan/parse errors.'));
/**
* Initialize a newly created instance to represent an error condition caused
* by a `analysis.setPriorityFiles` [request] that includes one or more files
* that are not being analyzed.
*/
- Response.unanalyzedPriorityFiles(String requestId, String fileNames) : this(
- requestId,
- error: new RequestError(RequestErrorCode.UNANALYZED_PRIORITY_FILES,
- "Unanalyzed files cannot be a priority: '$fileNames'"));
+ Response.unanalyzedPriorityFiles(String requestId, String fileNames)
+ : this(requestId,
+ error: new RequestError(RequestErrorCode.UNANALYZED_PRIORITY_FILES,
+ "Unanalyzed files cannot be a priority: '$fileNames'"));
/**
* Initialize a newly created instance to represent an error condition caused
* by a [request] that cannot be handled by any known handlers.
*/
- Response.unknownRequest(Request request) : this(request.id,
- error: new RequestError(
- RequestErrorCode.UNKNOWN_REQUEST, 'Unknown request'));
+ Response.unknownRequest(Request request)
+ : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.UNKNOWN_REQUEST, 'Unknown request'));
/**
* Initialize a newly created instance to represent an error condition caused
* by a [request] referencing a source that does not exist.
*/
- Response.unknownSource(Request request) : this(request.id,
- error: new RequestError(
- RequestErrorCode.UNKNOWN_SOURCE, 'Unknown source'));
+ Response.unknownSource(Request request)
+ : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.UNKNOWN_SOURCE, 'Unknown source'));
- Response.unsupportedFeature(String requestId, String message) : this(
- requestId,
- error: new RequestError(
- RequestErrorCode.UNSUPPORTED_FEATURE, message));
+ Response.unsupportedFeature(String requestId, String message)
+ : this(requestId,
+ error: new RequestError(
+ RequestErrorCode.UNSUPPORTED_FEATURE, message));
/**
* Return a table representing the structure of the Json object that will be
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index f9e48c58..4f0b490 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -47,6 +47,23 @@
change.addEdit(file, fileStamp, edit);
}
+String getReturnTypeString(engine.Element element) {
+ if (element is engine.ExecutableElement) {
+ if (element.kind == engine.ElementKind.SETTER) {
+ return null;
+ } else {
+ return element.returnType.toString();
+ }
+ } else if (element is engine.VariableElement) {
+ engine.DartType type = element.type;
+ return type != null ? type.displayName : 'dynamic';
+ } else if (element is engine.FunctionTypeAliasElement) {
+ return element.returnType.toString();
+ } else {
+ return null;
+ }
+}
+
/**
* Construct based on error information from the analyzer engine.
*/
@@ -86,7 +103,7 @@
String name = element.displayName;
String elementTypeParameters = _getTypeParametersString(element);
String elementParameters = _getParametersString(element);
- String elementReturnType = _getReturnTypeString(element);
+ String elementReturnType = getReturnTypeString(element);
ElementKind kind = newElementKind_fromEngineElement(element);
return new Element(kind, name, Element.makeFlags(
isPrivate: element.isPrivate,
@@ -103,7 +120,7 @@
/**
* Construct based on a value from the analyzer engine.
- * This does not take into account that
+ * This does not take into account that
* instances of ClassElement can be an enum and
* instances of FieldElement can be an enum constant.
* Use [newElementKind_fromEngineElement] where possible.
@@ -351,23 +368,6 @@
return '(' + sb.toString() + ')';
}
-String _getReturnTypeString(engine.Element element) {
- if (element is engine.ExecutableElement) {
- if (element.kind == engine.ElementKind.SETTER) {
- return null;
- } else {
- return element.returnType.toString();
- }
- } else if (element is engine.VariableElement) {
- engine.DartType type = element.type;
- return type != null ? type.displayName : 'dynamic';
- } else if (element is engine.FunctionTypeAliasElement) {
- return element.returnType.toString();
- } else {
- return null;
- }
-}
-
String _getTypeParametersString(engine.Element element) {
List<engine.TypeParameterElement> typeParameters;
if (element is engine.ClassElement) {
diff --git a/pkg/analysis_server/lib/src/server_options.dart b/pkg/analysis_server/lib/src/server_options.dart
new file mode 100644
index 0000000..2eff6d9
--- /dev/null
+++ b/pkg/analysis_server/lib/src/server_options.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.server_options;
+
+import 'dart:collection';
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:yaml/yaml.dart';
+
+//TODO: consider renaming (https://github.com/dart-lang/sdk/issues/23927)
+const _optionsFileName = '.dart_analysis_server.yaml';
+
+/// The shared options instance.
+ServerOptions _serverOptions;
+
+/// Server options.
+ServerOptions get serverOptions {
+ if (_serverOptions == null) {
+ _serverOptions = _loadOptions();
+ }
+ return _serverOptions;
+}
+
+/// Find the options file relative to the user's home directory.
+/// Returns `null` if there is none or the user's homedir cannot
+/// be derived from the platform's environment (e.g., `HOME` and
+/// `UserProfile` for mac/Linux and Windows respectively).
+File _findOptionsFile() {
+ String home;
+ Map<String, String> envVars = Platform.environment;
+ if (Platform.isMacOS || Platform.isLinux) {
+ home = envVars['HOME'];
+ } else if (Platform.isWindows) {
+ home = envVars['UserProfile'];
+ }
+
+ if (home == null) {
+ return null;
+ }
+
+ return new File(path.context.join(home, _optionsFileName));
+}
+
+ServerOptions _loadOptions() {
+ File optionsFile = _findOptionsFile();
+ try {
+ if (optionsFile != null && optionsFile.existsSync()) {
+ return new ServerOptions.fromFile(optionsFile);
+ }
+ } catch (e) {
+ // Fall through.
+ }
+ return new ServerOptions._empty();
+}
+
+/// Describes options captured in an external options file.
+/// `ServerOptions` are described in a file `dart_analysis_server.options`
+/// located in the user's home directory. Options are defined in YAML and
+/// read once and cached. In order for changes to be picked up, server needs
+/// to be restarted.
+class ServerOptions {
+ final Map<String, dynamic> _options = new HashMap<String, dynamic>();
+
+ /// Load options from the given [contents].
+ ServerOptions.fromContents(String contents) {
+ _readOptions(contents);
+ }
+
+ /// Load options from the given [options] file.
+ factory ServerOptions.fromFile(File options) =>
+ new ServerOptions.fromContents(options.readAsStringSync());
+
+ /// Create an empty options object.
+ ServerOptions._empty();
+
+ /// Get the value for `key` from the options file.
+ dynamic operator [](String key) => _options[key];
+
+ /// Get a String value for this `key` or [defaultValue] if undefined
+ /// or not a String.
+ String getStringValue(String key, {String defaultValue: null}) {
+ var value = _options[key];
+ if (value is String) {
+ return value;
+ }
+ return defaultValue;
+ }
+
+ /// Test whether the given [booleanPropertyKey] is set to the value `true`,
+ /// falling back to [defaultValue] if undefined.
+ /// For example:
+ /// myDebugOption1:true
+ /// myDebugOption2:TRUE # Also true (case and trailing whitespace are ignored).
+ /// myDebugOption3:false
+ /// myDebugOption4:off # Treated as `false`.
+ /// myDebugOption5:on # Also read as `false`.
+ bool isSet(String booleanPropertyKey, {bool defaultValue: false}) {
+ var value = _options[booleanPropertyKey];
+ if (value == null) {
+ return defaultValue;
+ }
+ return value == true;
+ }
+
+ void _readOptions(String contents) {
+ var doc = loadYaml(contents);
+ if (doc is YamlMap) {
+ doc.forEach((k, v) {
+ if (k is String) {
+ _options[k] = v;
+ }
+ });
+ }
+ }
+}
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 9fb70ba..b3a78e6 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
@@ -127,6 +127,9 @@
*/
List<DartCompletionContributor> computeFast(
DartCompletionRequest request, CompletionPerformance performance) {
+ bool isKeywordOrIdentifier(Token token) =>
+ token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER;
+
return performance.logElapseTime('computeFast', () {
CompilationUnit unit = context.parseCompilationUnit(source);
request.unit = unit;
@@ -140,12 +143,22 @@
var entity = request.target.entity;
Token token = entity is AstNode ? entity.beginToken : entity;
- if (token != null &&
- token.offset <= request.offset &&
- (token.type == TokenType.KEYWORD ||
- token.type == TokenType.IDENTIFIER)) {
- request.replacementOffset = token.offset;
- request.replacementLength = token.length;
+ if (token != null && request.offset < token.offset) {
+ token = token.previous;
+ }
+ if (token != null) {
+ if (request.offset == token.offset && !isKeywordOrIdentifier(token)) {
+ // If the insertion point is at the beginning of the current token
+ // and the current token is not an identifier
+ // then check the previous token to see if it should be replaced
+ token = token.previous;
+ }
+ if (token != null && isKeywordOrIdentifier(token)) {
+ if (token.offset <= request.offset && request.offset <= token.end) {
+ request.replacementOffset = token.offset;
+ request.replacementLength = token.length;
+ }
+ }
}
List<DartCompletionContributor> todo = new List.from(contributors);
diff --git a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
index 7eca2b5..9cfbb0d 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
@@ -14,6 +14,7 @@
import 'package:analysis_server/src/services/completion/local_suggestion_builder.dart';
import 'package:analysis_server/src/services/completion/optype.dart';
import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
/**
@@ -182,7 +183,7 @@
}
paramBuf.write(')');
protocol.Element element = createElement(
- protocol.ElementKind.CONSTRUCTOR, elemId,
+ request.source, protocol.ElementKind.CONSTRUCTOR, elemId,
parameters: paramBuf.toString());
element.returnType = classDecl.name.name;
CompletionSuggestion suggestion = new CompletionSuggestion(
@@ -277,8 +278,9 @@
if (isCaseLabel ? includeCaseLabels : includeStatementLabels) {
CompletionSuggestion suggestion = _addSuggestion(label.label);
if (suggestion != null) {
- suggestion.element =
- _createElement(protocol.ElementKind.LABEL, label.label);
+ suggestion.element = createElement(
+ request.source, protocol.ElementKind.LABEL, label.label,
+ returnType: NO_RETURN_TYPE);
}
}
}
@@ -331,17 +333,6 @@
}
return null;
}
-
- /**
- * Create a new protocol Element for inclusion in a completion suggestion.
- */
- protocol.Element _createElement(
- protocol.ElementKind kind, SimpleIdentifier id) {
- String name = id.name;
- int flags =
- protocol.Element.makeFlags(isPrivate: Identifier.isPrivateName(name));
- return new protocol.Element(kind, name, flags);
- }
}
/**
@@ -386,7 +377,7 @@
void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
if (optype.includeReturnValueSuggestions) {
CompletionSuggestion suggestion =
- createFieldSuggestion(fieldDecl, varDecl);
+ createFieldSuggestion(request.source, fieldDecl, varDecl);
if (suggestion != null) {
request.addSuggestion(suggestion);
}
@@ -547,7 +538,7 @@
id, isDeprecated, relevance, typeName, classDecl: classDecl);
if (suggestion != null) {
request.addSuggestion(suggestion);
- suggestion.element = createElement(elemKind, id,
+ suggestion.element = createElement(request.source, elemKind, id,
isAbstract: isAbstract,
isDeprecated: isDeprecated,
parameters: param != null ? param.toSource() : null,
diff --git a/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart
index 8014dd4..324e1a7 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart';
const DYNAMIC = 'dynamic';
@@ -19,16 +20,28 @@
/**
* Create a new protocol Element for inclusion in a completion suggestion.
*/
-protocol.Element createElement(protocol.ElementKind kind, SimpleIdentifier id,
+protocol.Element createElement(
+ Source source, protocol.ElementKind kind, SimpleIdentifier id,
{String parameters, TypeName returnType, bool isAbstract: false,
bool isDeprecated: false}) {
- String name = id != null ? id.name : '';
+ String name;
+ Location location;
+ if (id != null) {
+ name = id.name;
+ // TODO(danrubel) use lineInfo to determine startLine and startColumn
+ location = new Location(source.fullName, id.offset, id.length, 0, 0);
+ } else {
+ name = '';
+ location = new Location(source.fullName, -1, 0, 1, 0);
+ }
int flags = protocol.Element.makeFlags(
isAbstract: isAbstract,
isDeprecated: isDeprecated,
isPrivate: Identifier.isPrivateName(name));
return new protocol.Element(kind, name, flags,
- parameters: parameters, returnType: nameForType(returnType));
+ location: location,
+ parameters: parameters,
+ returnType: nameForType(returnType));
}
/**
@@ -36,13 +49,13 @@
* Return the new suggestion or `null` if it could not be created.
*/
CompletionSuggestion createFieldSuggestion(
- FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
+ Source source, FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
bool deprecated = isDeprecated(fieldDecl) || isDeprecated(varDecl);
TypeName type = fieldDecl.fields.type;
return createSuggestion(
varDecl.name, deprecated, DART_RELEVANCE_LOCAL_FIELD, type,
classDecl: fieldDecl.parent,
- element: createElement(protocol.ElementKind.FIELD, varDecl.name,
+ element: createElement(source, protocol.ElementKind.FIELD, varDecl.name,
returnType: type, isDeprecated: deprecated));
}
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index c9d88bcd..7ab13f9 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -543,7 +543,6 @@
if (identical(entity, node.expression)) {
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
- optype.includeVoidReturnSuggestions = true;
}
}
@@ -553,6 +552,21 @@
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
}
+ if (identical(entity, node.rightBracket)) {
+ if (node.members.isNotEmpty) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ optype.includeVoidReturnSuggestions = true;
+ }
+ }
+ if (entity is SwitchMember && entity != node.members.first) {
+ SwitchMember member = entity as SwitchMember;
+ if (offset <= member.offset) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ optype.includeVoidReturnSuggestions = true;
+ }
+ }
}
@override
diff --git a/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
index 5abb208..f3a9db4 100644
--- a/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
@@ -8,9 +8,12 @@
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart';
-import 'package:analysis_server/src/services/completion/local_suggestion_builder.dart';
+import 'package:analysis_server/src/services/completion/local_suggestion_builder.dart'
+ hide createSuggestion;
import 'package:analysis_server/src/services/completion/optype.dart';
import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
+import 'package:analysis_server/src/services/completion/suggestion_builder.dart'
+ show createSuggestion;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
@@ -134,7 +137,7 @@
if (fieldName != null && fieldName.length > 0) {
if (!referencedFields.contains(fieldName)) {
CompletionSuggestion suggestion =
- createFieldSuggestion(member, varDecl);
+ createFieldSuggestion(request.source, member, varDecl);
if (suggestion != null) {
request.addSuggestion(suggestion);
}
@@ -405,20 +408,8 @@
request.target.containingNode.parent is TypeName);
modified = true;
if (directive.deferredKeyword != null) {
- String completion = 'loadLibrary';
- CompletionSuggestion suggestion = new CompletionSuggestion(
- CompletionSuggestionKind.INVOCATION, DART_RELEVANCE_DEFAULT,
- completion, completion.length, 0, false, false,
- parameterNames: [],
- parameterTypes: [],
- requiredParameterCount: 0,
- hasNamedParameters: false,
- returnType: 'void');
- suggestion.element = new protocol.Element(
- protocol.ElementKind.FUNCTION, completion,
- protocol.Element.makeFlags(),
- parameters: '()', returnType: 'void');
- request.addSuggestion(suggestion);
+ FunctionElement loadLibFunct = library.loadLibraryFunction;
+ request.addSuggestion(createSuggestion(loadLibFunct));
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index 157a9e0..c6e376a 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -28,35 +28,10 @@
CompletionSuggestion createSuggestion(Element element,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
int relevance: DART_RELEVANCE_DEFAULT, Source importForSource}) {
- String nameForType(DartType type) {
- if (type == null) {
- return DYNAMIC;
- }
- String name = type.displayName;
- if (name == null || name.length <= 0) {
- return DYNAMIC;
- }
- //TODO (danrubel) include type arguments ??
- return name;
+ if (element is ExecutableElement && element.isOperator) {
+ // Do not include operators in suggestions
+ return null;
}
-
- String returnType = null;
- if (element is ExecutableElement) {
- if (element.isOperator) {
- // Do not include operators in suggestions
- return null;
- }
- if (element is PropertyAccessorElement && element.isSetter) {
- // no return type
- } else {
- returnType = nameForType(element.returnType);
- }
- } else if (element is VariableElement) {
- returnType = nameForType(element.type);
- } else if (element is FunctionTypeAliasElement) {
- returnType = nameForType(element.returnType);
- }
-
String completion = element.displayName;
bool isDeprecated = element.isDeprecated;
CompletionSuggestion suggestion = new CompletionSuggestion(kind,
@@ -67,7 +42,7 @@
if (enclosingElement is ClassElement) {
suggestion.declaringType = enclosingElement.displayName;
}
- suggestion.returnType = returnType;
+ suggestion.returnType = getReturnTypeString(element);
if (element is ExecutableElement && element is! PropertyAccessorElement) {
suggestion.parameterNames = element.parameters
.map((ParameterElement parameter) => parameter.name)
@@ -476,6 +451,12 @@
@override
visitCompilationUnitElement(CompilationUnitElement element) {
element.visitChildren(this);
+ LibraryElement containingLibrary = element.library;
+ if (containingLibrary != null) {
+ for (var lib in containingLibrary.exportedLibraries) {
+ lib.visitChildren(this);
+ }
+ }
}
@override
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 9c5e9ba..cf87d27 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -399,13 +399,19 @@
return;
}
Expression returnValue = (body as ExpressionFunctionBody).expression;
+ DartType returnValueType = returnValue.staticType;
+ String returnValueCode = _getNodeText(returnValue);
// prepare prefix
String prefix = utils.getNodePrefix(body.parent);
- // add change
String indent = utils.getIndent(1);
- String returnSource = 'return ' + _getNodeText(returnValue);
- String newBodySource = '{$eol$prefix$indent$returnSource;$eol$prefix}';
- _addReplaceEdit(rangeNode(body), newBodySource);
+ // add change
+ String statementCode =
+ (returnValueType.isVoid ? '' : 'return ') + returnValueCode;
+ SourceBuilder sb = new SourceBuilder(file, body.offset);
+ sb.append('{$eol$prefix$indent$statementCode;');
+ sb.setExitOffset();
+ sb.append('$eol$prefix}');
+ _insertBuilder(sb, body.length);
// add proposal
_addAssist(DartAssistKind.CONVERT_INTO_BLOCK_BODY, []);
}
@@ -423,13 +429,14 @@
_coverageMarker();
return;
}
- if (statements[0] is! ReturnStatement) {
- _coverageMarker();
- return;
- }
- ReturnStatement returnStatement = statements[0] as ReturnStatement;
+ Statement onlyStatement = statements.first;
// prepare returned expression
- Expression returnExpression = returnStatement.expression;
+ Expression returnExpression;
+ if (onlyStatement is ReturnStatement) {
+ returnExpression = onlyStatement.expression;
+ } else if (onlyStatement is ExpressionStatement) {
+ returnExpression = onlyStatement.expression;
+ }
if (returnExpression == null) {
_coverageMarker();
return;
@@ -484,8 +491,8 @@
// check number of references
{
int numOfReferences = 0;
- AstVisitor visitor = new _SimpleIdentifierRecursiveAstVisitor(
- (SimpleIdentifier node) {
+ AstVisitor visitor =
+ new _SimpleIdentifierRecursiveAstVisitor((SimpleIdentifier node) {
if (node.staticElement == parameterElement) {
numOfReferences++;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 46ae81f..dde87a0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/edit/fix/fix_core.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -15,13 +16,14 @@
* reported after it's source was analyzed in the given [context]. The [plugin]
* is used to get the list of fix contributors.
*/
-List<Fix> computeFixes(
- ServerPlugin plugin, AnalysisContext context, AnalysisError error) {
+List<Fix> computeFixes(ServerPlugin plugin, ResourceProvider resourceProvider,
+ AnalysisContext context, AnalysisError error) {
List<Fix> fixes = <Fix>[];
List<FixContributor> contributors = plugin.fixContributors;
for (FixContributor contributor in contributors) {
try {
- List<Fix> contributedFixes = contributor.computeFixes(context, error);
+ List<Fix> contributedFixes =
+ contributor.computeFixes(resourceProvider, context, error);
if (contributedFixes != null) {
fixes.addAll(contributedFixes);
}
@@ -44,7 +46,8 @@
static const ADD_FIELD_FORMAL_PARAMETERS = const FixKind(
'ADD_FIELD_FORMAL_PARAMETERS', 30, "Add final field formal parameters");
static const ADD_MISSING_PARAMETER_POSITIONAL = const FixKind(
- 'ADD_MISSING_PARAMETER_POSITIONAL', 31,
+ 'ADD_MISSING_PARAMETER_POSITIONAL',
+ 31,
"Add optional positional parameter");
static const ADD_MISSING_PARAMETER_REQUIRED = const FixKind(
'ADD_MISSING_PARAMETER_REQUIRED', 30, "Add required parameter");
@@ -53,7 +56,8 @@
static const ADD_PART_OF =
const FixKind('ADD_PART_OF', 50, "Add 'part of' directive");
static const ADD_SUPER_CONSTRUCTOR_INVOCATION = const FixKind(
- 'ADD_SUPER_CONSTRUCTOR_INVOCATION', 50,
+ 'ADD_SUPER_CONSTRUCTOR_INVOCATION',
+ 50,
"Add super constructor {0} invocation");
static const CHANGE_TO = const FixKind('CHANGE_TO', 49, "Change to '{0}'");
static const CHANGE_TO_STATIC_ACCESS = const FixKind(
@@ -63,7 +67,8 @@
static const CREATE_CONSTRUCTOR =
const FixKind('CREATE_CONSTRUCTOR', 50, "Create constructor '{0}'");
static const CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS = const FixKind(
- 'CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS', 50,
+ 'CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS',
+ 50,
"Create constructor for final fields");
static const CREATE_CONSTRUCTOR_SUPER = const FixKind(
'CREATE_CONSTRUCTOR_SUPER', 50, "Create constructor to call {0}");
@@ -98,10 +103,12 @@
static const REMOVE_DEAD_CODE =
const FixKind('REMOVE_DEAD_CODE', 50, "Remove dead code");
static const REMOVE_PARAMETERS_IN_GETTER_DECLARATION = const FixKind(
- 'REMOVE_PARAMETERS_IN_GETTER_DECLARATION', 50,
+ 'REMOVE_PARAMETERS_IN_GETTER_DECLARATION',
+ 50,
"Remove parameters in getter declaration");
static const REMOVE_PARENTHESIS_IN_GETTER_INVOCATION = const FixKind(
- 'REMOVE_PARENTHESIS_IN_GETTER_INVOCATION', 50,
+ 'REMOVE_PARENTHESIS_IN_GETTER_INVOCATION',
+ 50,
"Remove parentheses in getter invocation");
static const REMOVE_UNNECASSARY_CAST =
const FixKind('REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast");
@@ -118,11 +125,13 @@
static const REPLACE_VAR_WITH_DYNAMIC = const FixKind(
'REPLACE_VAR_WITH_DYNAMIC', 50, "Replace 'var' with 'dynamic'");
static const REPLACE_RETURN_TYPE_FUTURE = const FixKind(
- 'REPLACE_RETURN_TYPE_FUTURE', 50,
+ 'REPLACE_RETURN_TYPE_FUTURE',
+ 50,
"Return 'Future' from 'async' function");
static const USE_CONST = const FixKind('USE_CONST', 50, "Change to constant");
static const USE_EFFECTIVE_INTEGER_DIVISION = const FixKind(
- 'USE_EFFECTIVE_INTEGER_DIVISION', 50,
+ 'USE_EFFECTIVE_INTEGER_DIVISION',
+ 50,
"Use effective integer division ~/");
static const USE_EQ_EQ_NULL =
const FixKind('USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'");
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 cb695b8..3c8f1a7 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -5,6 +5,7 @@
library analysis_server.src.services.correction.fix_internal;
import 'dart:collection';
+import 'dart:core' hide Resource;
import 'package:analysis_server/edit/fix/fix_core.dart';
import 'package:analysis_server/edit/fix/fix_dart.dart';
@@ -22,6 +23,7 @@
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/services/search/hierarchy.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -33,6 +35,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:path/path.dart';
+import 'package:path/path.dart' as ppp;
/**
* A predicate is a one-argument function that returns a boolean value.
@@ -44,8 +47,9 @@
*/
class DefaultFixContributor extends DartFixContributor {
@override
- List<Fix> internalComputeFixes(CompilationUnit unit, AnalysisError error) {
- FixProcessor processor = new FixProcessor(unit, error);
+ List<Fix> internalComputeFixes(ResourceProvider resourceProvider,
+ CompilationUnit unit, AnalysisError error) {
+ FixProcessor processor = new FixProcessor(resourceProvider, unit, error);
return processor.compute();
}
}
@@ -56,6 +60,7 @@
class FixProcessor {
static const int MAX_LEVENSHTEIN_DISTANCE = 3;
+ final ResourceProvider resourceProvider;
final CompilationUnit unit;
final AnalysisError error;
AnalysisContext context;
@@ -83,7 +88,7 @@
AstNode node;
AstNode coveredNode;
- FixProcessor(this.unit, this.error) {
+ FixProcessor(this.resourceProvider, this.unit, this.error) {
unitElement = unit.element;
context = unitElement.context;
unitSource = unitElement.source;
@@ -207,8 +212,7 @@
if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
_addFix_createConstructor_named();
}
- if (errorCode ==
- StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
+ if (errorCode == StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
errorCode ==
@@ -249,6 +253,7 @@
bool isAsync = _addFix_addAsync();
if (!isAsync) {
_addFix_undefinedClassAccessor_useSimilar();
+ _addFix_createClass();
_addFix_createField();
_addFix_createGetter();
_addFix_createFunction_forFunctionType();
@@ -423,7 +428,8 @@
CorrectionUtils partUtils = new CorrectionUtils(partUnit);
CorrectionUtils_InsertDesc desc = partUtils.getInsertDescTop();
String libraryName = unitLibraryElement.name;
- _addInsertEdit(desc.offset,
+ _addInsertEdit(
+ desc.offset,
'${desc.prefix}part of $libraryName;$eol${desc.suffix}',
partUnit.element);
_addFix(DartFixKind.ADD_PART_OF, []);
@@ -440,17 +446,20 @@
void _addFix_createClass() {
Element prefixElement = null;
String name = null;
+ SimpleIdentifier nameNode;
if (node is SimpleIdentifier) {
AstNode parent = node.parent;
if (parent is PrefixedIdentifier) {
PrefixedIdentifier prefixedIdentifier = parent;
prefixElement = prefixedIdentifier.prefix.staticElement;
parent = prefixedIdentifier.parent;
+ nameNode = prefixedIdentifier.identifier;
name = prefixedIdentifier.identifier.name;
} else {
- name = (node as SimpleIdentifier).name;
+ nameNode = node;
+ name = nameNode.name;
}
- if (parent is! TypeName) {
+ if (!_mayBeTypeIdentifier(nameNode)) {
return;
}
} else {
@@ -1050,8 +1059,7 @@
if (source != null) {
String file = source.fullName;
if (isAbsolute(file)) {
- String libName = removeEnd(source.shortName, '.dart');
- libName = libName.replaceAll('_', '.');
+ String libName = _computeLibraryName(file);
SourceEdit edit = new SourceEdit(0, 0, 'library $libName;$eol$eol');
doSourceChange_addSourceEdit(change, context, source, edit);
_addFix(DartFixKind.CREATE_FILE, [source.shortName]);
@@ -1344,10 +1352,8 @@
if (prefix != null) {
SourceRange range = rf.rangeStartLength(node, 0);
_addReplaceEdit(range, '${prefix.displayName}.');
- _addFix(DartFixKind.IMPORT_LIBRARY_PREFIX, [
- libraryElement.displayName,
- prefix.displayName
- ]);
+ _addFix(DartFixKind.IMPORT_LIBRARY_PREFIX,
+ [libraryElement.displayName, prefix.displayName]);
continue;
}
// may be update "show" directive
@@ -1657,7 +1663,8 @@
void _addFix_undefinedClass_useSimilar() {
if (_mayBeTypeIdentifier(node)) {
String name = (node as SimpleIdentifier).name;
- _ClosestElementFinder finder = new _ClosestElementFinder(name,
+ _ClosestElementFinder finder = new _ClosestElementFinder(
+ name,
(Element element) => element is ClassElement,
MAX_LEVENSHTEIN_DISTANCE);
// find closest element
@@ -1790,7 +1797,8 @@
void _addFix_undefinedFunction_useSimilar() {
if (node is SimpleIdentifier) {
String name = (node as SimpleIdentifier).name;
- _ClosestElementFinder finder = new _ClosestElementFinder(name,
+ _ClosestElementFinder finder = new _ClosestElementFinder(
+ name,
(Element element) => element is FunctionElement,
MAX_LEVENSHTEIN_DISTANCE);
// this library
@@ -2052,9 +2060,16 @@
* Prepares proposal for creating function corresponding to the given
* [FunctionType].
*/
- void _addProposal_createFunction(FunctionType functionType, String name,
- Source targetSource, int insertOffset, bool isStatic, String prefix,
- String sourcePrefix, String sourceSuffix, Element target) {
+ void _addProposal_createFunction(
+ FunctionType functionType,
+ String name,
+ Source targetSource,
+ int insertOffset,
+ bool isStatic,
+ String prefix,
+ String sourcePrefix,
+ String sourceSuffix,
+ Element target) {
// build method source
String targetFile = targetSource.fullName;
SourceBuilder sb = new SourceBuilder(targetFile, insertOffset);
@@ -2154,8 +2169,15 @@
sourcePrefix = eol;
}
String sourceSuffix = eol;
- _addProposal_createFunction(functionType, name, targetSource, insertOffset,
- _inStaticContext(), prefix, sourcePrefix, sourceSuffix,
+ _addProposal_createFunction(
+ functionType,
+ name,
+ targetSource,
+ insertOffset,
+ _inStaticContext(),
+ prefix,
+ sourcePrefix,
+ sourceSuffix,
targetClassElement);
// add proposal
_addFix(DartFixKind.CREATE_METHOD, [name]);
@@ -2274,6 +2296,51 @@
}
/**
+ * Computes the name of the library at the given [path].
+ * See https://www.dartlang.org/articles/style-guide/#names for conventions.
+ */
+ String _computeLibraryName(String path) {
+ Context pathContext = resourceProvider.pathContext;
+ String packageFolder = _computePackageFolder(path);
+ if (packageFolder == null) {
+ return pathContext.basenameWithoutExtension(path);
+ }
+ String packageName = pathContext.basename(packageFolder);
+ String relPath = pathContext.relative(path, from: packageFolder);
+ List<String> relPathParts = pathContext.split(relPath);
+ if (relPathParts.isNotEmpty) {
+ if (relPathParts[0].toLowerCase() == 'lib') {
+ relPathParts.removeAt(0);
+ }
+ {
+ String nameWithoutExt = pathContext.withoutExtension(relPathParts.last);
+ relPathParts[relPathParts.length - 1] = nameWithoutExt;
+ }
+ }
+ return packageName + '.' + relPathParts.join('.');
+ }
+
+ /**
+ * Returns the path of the folder which contains the given [path].
+ */
+ String _computePackageFolder(String path) {
+ Context pathContext = resourceProvider.pathContext;
+ String pubspecFolder = dirname(path);
+ while (true) {
+ if (resourceProvider
+ .getResource(pathContext.join(pubspecFolder, 'pubspec.yaml'))
+ .exists) {
+ return pubspecFolder;
+ }
+ String pubspecFolderNew = pathContext.dirname(pubspecFolder);
+ if (pubspecFolderNew == pubspecFolder) {
+ return null;
+ }
+ pubspecFolder = pubspecFolderNew;
+ }
+ }
+
+ /**
* @return the string to display as the name of the given constructor in a proposal name.
*/
String _getConstructorProposalName(ConstructorElement constructor) {
@@ -2611,24 +2678,27 @@
return <String>['arg$index'];
}
+ static bool _isNameOfType(String name) {
+ if (name.isEmpty) {
+ return false;
+ }
+ String firstLetter = name.substring(0, 1);
+ if (firstLetter.toUpperCase() != firstLetter) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Returns `true` if [node] is a type name.
*/
static bool _mayBeTypeIdentifier(AstNode node) {
if (node is SimpleIdentifier) {
AstNode parent = node.parent;
- if (parent is Annotation) {
- return true;
- }
if (parent is TypeName) {
return true;
}
- if (parent is MethodInvocation) {
- return parent.realTarget == node;
- }
- if (parent is PrefixedIdentifier) {
- return parent.prefix == node;
- }
+ return _isNameOfType(node.name);
}
return false;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
new file mode 100644
index 0000000..b12ecb1
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
@@ -0,0 +1,248 @@
+// 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 services.src.refactoring.organize_directives;
+
+import 'package:analysis_server/src/protocol.dart' hide AnalysisError, Element;
+import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'dart:math';
+
+/**
+ * Organizer of directives in the [unit].
+ */
+class DirectiveOrganizer {
+ final String initialCode;
+ final CompilationUnit unit;
+ final List<AnalysisError> errors;
+ final bool removeUnresolved;
+ final bool removeUnused;
+ String code;
+ String endOfLine;
+
+ DirectiveOrganizer(this.initialCode, this.unit, this.errors,
+ {this.removeUnresolved: true, this.removeUnused: true}) {
+ this.code = initialCode;
+ this.endOfLine = getEOL(code);
+ }
+
+ /**
+ * Return the [SourceEdit]s that organize directives in the [unit].
+ */
+ List<SourceEdit> organize() {
+ _organizeDirectives();
+ // prepare edits
+ List<SourceEdit> edits = <SourceEdit>[];
+ if (code != initialCode) {
+ int suffixLength = findCommonSuffix(initialCode, code);
+ SourceEdit edit = new SourceEdit(0, initialCode.length - suffixLength,
+ code.substring(0, code.length - suffixLength));
+ edits.add(edit);
+ }
+ return edits;
+ }
+
+ bool _isUnresolvedUri(UriBasedDirective directive) {
+ for (AnalysisError error in errors) {
+ if (error.errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST &&
+ directive.uri.offset == error.offset) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _isUnusedImport(UriBasedDirective directive) {
+ for (AnalysisError error in errors) {
+ if (error.errorCode == HintCode.UNUSED_IMPORT &&
+ directive.uri.offset == error.offset) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Oraganize all [Directive]s.
+ */
+ void _organizeDirectives() {
+ List<_DirectiveInfo> directives = [];
+ for (Directive directive in unit.directives) {
+ if (directive is UriBasedDirective) {
+ _DirectivePriority priority = getDirectivePriority(directive);
+ if (priority != null) {
+ int offset = directive.offset;
+ int length = directive.length;
+ String text = code.substring(offset, offset + length);
+ String uriContent = directive.uri.stringValue;
+ directives
+ .add(new _DirectiveInfo(directive, priority, uriContent, text));
+ }
+ }
+ }
+ // nothing to do
+ if (directives.isEmpty) {
+ return;
+ }
+ int firstDirectiveOffset = directives.first.directive.offset;
+ int lastDirectiveEnd = directives.last.directive.end;
+ // sort
+ directives.sort();
+ // append directives with grouping
+ String directivesCode;
+ {
+ StringBuffer sb = new StringBuffer();
+ _DirectivePriority currentPriority = null;
+ for (_DirectiveInfo directiveInfo in directives) {
+ if (removeUnresolved && _isUnresolvedUri(directiveInfo.directive)) {
+ continue;
+ }
+ if (removeUnused && _isUnusedImport(directiveInfo.directive)) {
+ continue;
+ }
+ if (currentPriority != directiveInfo.priority) {
+ if (sb.length != 0) {
+ sb.write(endOfLine);
+ }
+ currentPriority = directiveInfo.priority;
+ }
+ sb.write(directiveInfo.text);
+ sb.write(endOfLine);
+ }
+ directivesCode = sb.toString();
+ directivesCode = directivesCode.trimRight();
+ }
+ // append comment tokens which otherwise would be removed completely
+ {
+ bool firstCommentToken = true;
+ Token token = unit.beginToken;
+ while (token != null &&
+ token.type != TokenType.EOF &&
+ token.end < lastDirectiveEnd) {
+ Token commentToken = token.precedingComments;
+ while (commentToken != null) {
+ int offset = commentToken.offset;
+ int end = commentToken.end;
+ if (offset > firstDirectiveOffset && offset < lastDirectiveEnd) {
+ if (firstCommentToken) {
+ directivesCode += endOfLine;
+ firstCommentToken = false;
+ }
+ directivesCode += code.substring(offset, end) + endOfLine;
+ }
+ commentToken = commentToken.next;
+ }
+ token = token.next;
+ }
+ }
+ // prepare code
+ String beforeDirectives = code.substring(0, firstDirectiveOffset);
+ String afterDirectives = code.substring(lastDirectiveEnd);
+ code = beforeDirectives + directivesCode + afterDirectives;
+ }
+
+ static _DirectivePriority getDirectivePriority(UriBasedDirective directive) {
+ String uriContent = directive.uri.stringValue;
+ if (directive is ImportDirective) {
+ if (uriContent.startsWith("dart:")) {
+ return _DirectivePriority.IMPORT_SDK;
+ } else if (uriContent.startsWith("package:")) {
+ return _DirectivePriority.IMPORT_PKG;
+ } else if (uriContent.contains('://')) {
+ return _DirectivePriority.IMPORT_OTHER;
+ } else {
+ return _DirectivePriority.IMPORT_REL;
+ }
+ }
+ if (directive is ExportDirective) {
+ if (uriContent.startsWith("dart:")) {
+ return _DirectivePriority.EXPORT_SDK;
+ } else if (uriContent.startsWith("package:")) {
+ return _DirectivePriority.EXPORT_PKG;
+ } else if (uriContent.contains('://')) {
+ return _DirectivePriority.EXPORT_OTHER;
+ } else {
+ return _DirectivePriority.EXPORT_REL;
+ }
+ }
+ if (directive is PartDirective) {
+ return _DirectivePriority.PART;
+ }
+ return null;
+ }
+
+ /**
+ * Return the EOL to use for [code].
+ */
+ static String getEOL(String code) {
+ if (code.contains('\r\n')) {
+ return '\r\n';
+ } else {
+ return '\n';
+ }
+ }
+}
+
+class _DirectiveInfo implements Comparable<_DirectiveInfo> {
+ final UriBasedDirective directive;
+ final _DirectivePriority priority;
+ final String uri;
+ final String text;
+
+ _DirectiveInfo(this.directive, this.priority, this.uri, this.text);
+
+ @override
+ int compareTo(_DirectiveInfo other) {
+ if (priority == other.priority) {
+ return _compareUri(uri, other.uri);
+ }
+ return priority.ordinal - other.priority.ordinal;
+ }
+
+ @override
+ String toString() => '(priority=$priority; text=$text)';
+
+ static int _compareUri(String a, String b) {
+ List<String> aList = _splitUri(a);
+ List<String> bList = _splitUri(b);
+ int result;
+ if ((result = aList[0].compareTo(bList[0])) != 0) return result;
+ if ((result = aList[1].compareTo(bList[1])) != 0) return result;
+ return 0;
+ }
+
+ /**
+ * Split the given [uri] like `package:some.name/and/path.dart` into a list
+ * like `[package:some.name, and/path.dart]`.
+ */
+ static List<String> _splitUri(String uri) {
+ int index = uri.indexOf('/');
+ if (index == -1) {
+ return <String>[uri, ''];
+ }
+ return <String>[uri.substring(0, index), uri.substring(index + 1)];
+ }
+}
+
+class _DirectivePriority {
+ static const IMPORT_SDK = const _DirectivePriority('IMPORT_SDK', 0);
+ static const IMPORT_PKG = const _DirectivePriority('IMPORT_PKG', 1);
+ static const IMPORT_OTHER = const _DirectivePriority('IMPORT_OTHER', 2);
+ static const IMPORT_REL = const _DirectivePriority('IMPORT_REL', 3);
+ static const EXPORT_SDK = const _DirectivePriority('EXPORT_SDK', 4);
+ static const EXPORT_PKG = const _DirectivePriority('EXPORT_PKG', 5);
+ static const EXPORT_OTHER = const _DirectivePriority('EXPORT_OTHER', 6);
+ static const EXPORT_REL = const _DirectivePriority('EXPORT_REL', 7);
+ static const PART = const _DirectivePriority('PART', 8);
+
+ final String name;
+ final int ordinal;
+
+ const _DirectivePriority(this.name, this.ordinal);
+
+ @override
+ String toString() => name;
+}
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index 1968766..d5abd12 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -11,10 +11,10 @@
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/local_file_index.dart';
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
import 'package:analysis_server/uri/resolver_provider.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:plugin/plugin.dart';
@@ -81,9 +81,8 @@
}
analysisServer = new AnalysisServer(serverChannel, resourceProvider,
- new OptimizingPubPackageMapProvider(resourceProvider, defaultSdk),
- index, serverPlugin, analysisServerOptions, defaultSdk,
- instrumentationService,
+ new PubPackageMapProvider(resourceProvider, defaultSdk), index,
+ serverPlugin, analysisServerOptions, defaultSdk, instrumentationService,
contextManager: contextManager,
packageResolverProvider: packageResolverProvider,
rethrowExceptions: false);
diff --git a/pkg/analysis_server/lib/src/source/optimizing_pub_package_map_provider.dart b/pkg/analysis_server/lib/src/source/optimizing_pub_package_map_provider.dart
deleted file mode 100644
index deeee77..0000000
--- a/pkg/analysis_server/lib/src/source/optimizing_pub_package_map_provider.dart
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library source.optimizing_pub_package_map_provider;
-
-import 'dart:core' hide Resource;
-
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/source/package_map_provider.dart';
-import 'package:analyzer/source/pub_package_map_provider.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
-
-/**
- * Extension of [PackageMapInfo] that tracks the modification timestamps of
- * pub dependencies. This allows the analysis server to avoid making redundant
- * calls to "pub list" when nothing has changed.
- */
-class OptimizingPubPackageMapInfo extends PackageMapInfo {
- /**
- * Map from file path to the file's modification timestamp prior to running
- * "pub list". Since the set of dependencies is not always known prior to
- * running "pub list", some or all of the dependencies may be missing from
- * this map.
- */
- final Map<String, int> modificationTimes;
-
- OptimizingPubPackageMapInfo(Map<String, List<Folder>> packageMap,
- Set<String> dependencies, this.modificationTimes)
- : super(packageMap, dependencies);
-
- /**
- * Return `true` if the given [path] is listed as a dependency, and we cannot
- * prove using modification timestamps that it is unchanged.
- * [resourceProvider] is used (if necessary) to read the [path]'s
- * modification time.
- */
- bool isChangedDependency(String path, ResourceProvider resourceProvider) {
- if (!dependencies.contains(path)) {
- // Path is not a dependency.
- return false;
- }
- int lastModificationTime = modificationTimes[path];
- if (lastModificationTime != null) {
- Resource resource = resourceProvider.getResource(path);
- if (resource is File) {
- try {
- if (resource.modificationStamp == lastModificationTime) {
- // Path is a dependency, but it hasn't changed since the last run
- // of "pub list".
- return false;
- }
- } on FileSystemException {
- // Path is a dependency, but we can't read its timestamp. Assume
- // it's changed to be safe.
- }
- }
- }
- // Path is a dependency, and we couldn't prove that it hadn't changed.
- // Assume it's changed to be safe.
- return true;
- }
-}
-
-/**
- * Extension of [PubPackageMapProvider] that outputs additional information to
- * allow the analysis server to avoid making redundant calls to "pub list" when
- * nothing has changed.
- */
-class OptimizingPubPackageMapProvider extends PubPackageMapProvider {
- OptimizingPubPackageMapProvider(
- ResourceProvider resourceProvider, DirectoryBasedDartSdk sdk, [RunPubList runPubList])
- : super(resourceProvider, sdk, runPubList);
-
- /**
- * Compute a package map for the given folder by executing "pub list". If
- * [previousInfo] is provided, it is used as a guess of which files the
- * package map is likely to depend on; the modification times of those files
- * are captured prior to executing "pub list" so that they can be used to
- * avoid making redundant calls to "pub list" in the future.
- *
- * Also, in the case where dependencies can't be determined because of an
- * error, the dependencies from [previousInfo] will be preserved.
- */
- OptimizingPubPackageMapInfo computePackageMap(Folder folder,
- [OptimizingPubPackageMapInfo previousInfo]) {
- // Prior to running "pub list", read the modification timestamps of all of
- // the old dependencies (if known).
- Map<String, int> modificationTimes = <String, int>{};
- if (previousInfo != null) {
- for (String path in previousInfo.dependencies) {
- Resource resource = resourceProvider.getResource(path);
- if (resource is File) {
- try {
- modificationTimes[path] = resource.modificationStamp;
- } on FileSystemException {
- // File no longer exists. Don't record a timestamp for it; this
- // will ensure that if the file reappears, we will re-run "pub
- // list" regardless of the timestamp it reappears with.
- }
- }
- }
- }
-
- // Try running "pub list".
- PackageMapInfo info = super.computePackageMap(folder);
- if (info == null) {
- // Computing the package map resulted in an error. Merge the old
- // dependencies with the new ones, if possible.
- info = super.computePackageMapError(folder);
- if (previousInfo != null) {
- info.dependencies.addAll(previousInfo.dependencies);
- }
- }
-
- // Discard any elements of modificationTimes that are no longer
- // dependencies.
- if (previousInfo != null) {
- for (String dependency
- in previousInfo.dependencies.difference(info.dependencies)) {
- modificationTimes.remove(dependency);
- }
- }
-
- // Bundle the modificationTimes with the other info.
- return new OptimizingPubPackageMapInfo(
- info.packageMap, info.dependencies, modificationTimes);
- }
-
- @override
- PackageMapInfo computePackageMapError(Folder folder) {
- // Return null to indicate to our override of computePackageMap that there
- // was an error, so it can compute dependencies correctly.
- return null;
- }
-}
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 0a053bd..5b5236c 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -1042,7 +1042,7 @@
List<Folder> folders = folderMap.keys.toList();
folders.sort((Folder first, Folder second) =>
first.shortName.compareTo(second.shortName));
- AnalysisOptionsImpl options = analysisServer.contextManager.defaultOptions;
+ AnalysisOptionsImpl options = analysisServer.defaultContextOptions;
ServerOperationQueue operationQueue = analysisServer.operationQueue;
buffer.write('<h3>Analysis Domain</h3>');
@@ -1084,8 +1084,6 @@
_writeOption(
buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
_writeOption(buffer, 'Cache size', options.cacheSize);
- _writeOption(buffer, 'Enable null-aware operators',
- options.enableNullAwareOperators);
_writeOption(
buffer, 'Enable strict call checks', options.enableStrictCallChecks);
_writeOption(buffer, 'Generate hints', options.hint);
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index a9cb19b..2b14dd6 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,7 +6,7 @@
environment:
sdk: '>=1.9.0 <2.0.0'
dependencies:
- analyzer: '>=0.25.3-alpha.0 <0.26.0'
+ analyzer: '>=0.26.0-alpha.0 <0.27.0'
args: '>=0.13.0 <0.14.0'
dart_style: '>=0.1.7 <0.2.0'
logging: any
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index 14203c9..4cc0a2f 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -99,7 +99,7 @@
// remove context, causes sending an "invalid file" error
{
Folder projectFolder = resourceProvider.getResource(projectPath);
- server.contextManager.removeContext(projectFolder);
+ server.contextManager.callbacks.removeContext(projectFolder, <String>[]);
}
// wait for an error response
return serverChannel.waitForResponse(request).then((Response response) {
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index 1de99e4..752ee27 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -28,19 +28,6 @@
createProject();
}
- test_afterAnalysisComplete() async {
- addTestFile('''
-main() {
- var test = 0;
- print(test);
-}
-''');
- await waitForTasksFinished();
- await _getNavigation(testFile, testCode.indexOf('test);'), 0);
- assertHasRegion('test);');
- assertHasTarget('test = 0');
- }
-
test_beforeAnalysisComplete() async {
addTestFile('''
main() {
@@ -68,6 +55,36 @@
return _checkInvalid(file, -1, -1);
}
+ test_multipleRegions() async {
+ addTestFile('''
+main() {
+ var aaa = 1;
+ var bbb = 2;
+ var ccc = 3;
+ var ddd = 4;
+ print(aaa + bbb + ccc + ddd);
+}
+''');
+ await waitForTasksFinished();
+ // request navigation
+ String navCode = ' + bbb + ';
+ await _getNavigation(testFile, testCode.indexOf(navCode), navCode.length);
+ // verify
+ {
+ assertHasRegion('aaa +');
+ assertHasTarget('aaa = 1');
+ }
+ {
+ assertHasRegion('bbb +');
+ assertHasTarget('bbb = 2');
+ }
+ {
+ assertHasRegion('ccc +');
+ assertHasTarget('ccc = 3');
+ }
+ assertNoRegionAt('ddd)');
+ }
+
test_removeContextAfterRequest() async {
addTestFile('''
main() {
@@ -82,7 +99,7 @@
// remove context, causes sending an "invalid file" error
{
Folder projectFolder = resourceProvider.getResource(projectPath);
- server.contextManager.removeContext(projectFolder);
+ server.contextManager.callbacks.removeContext(projectFolder, <String>[]);
}
// wait for an error response
Response response = await serverChannel.waitForResponse(request);
@@ -90,6 +107,32 @@
expect(response.error.code, RequestErrorCode.GET_NAVIGATION_INVALID_FILE);
}
+ test_zeroLength_end() async {
+ addTestFile('''
+main() {
+ var test = 0;
+ print(test);
+}
+''');
+ await waitForTasksFinished();
+ await _getNavigation(testFile, testCode.indexOf(');'), 0);
+ assertHasRegion('test);');
+ assertHasTarget('test = 0');
+ }
+
+ test_zeroLength_start() async {
+ addTestFile('''
+main() {
+ var test = 0;
+ print(test);
+}
+''');
+ await waitForTasksFinished();
+ await _getNavigation(testFile, testCode.indexOf('test);'), 0);
+ assertHasRegion('test);');
+ assertHasTarget('test = 0');
+ }
+
_checkInvalid(String file, int offset, int length) async {
Request request = _createGetNavigationRequest(file, offset, length);
Response response = await serverChannel.sendRequest(request);
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 6c440471ca..09de3e8 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -18,6 +18,155 @@
defineReflectiveTests(AnalysisNotificationNavigationTest);
}
+class AbstractNavigationTest extends AbstractAnalysisTest {
+ List<NavigationRegion> regions;
+ List<NavigationTarget> targets;
+ List<String> targetFiles;
+
+ NavigationRegion testRegion;
+ List<int> testTargetIndexes;
+ NavigationTarget testTarget;
+
+ /**
+ * Validates that there is a target in [testTargetIndexes] with [file],
+ * at [offset] and with the given [length].
+ */
+ void assertHasFileTarget(String file, int offset, int length) {
+ List<NavigationTarget> testTargets =
+ testTargetIndexes.map((int index) => targets[index]).toList();
+ for (NavigationTarget target in testTargets) {
+ if (targetFiles[target.fileIndex] == file &&
+ target.offset == offset &&
+ target.length == length) {
+ testTarget = target;
+ return;
+ }
+ }
+ fail(
+ 'Expected to find target (file=$file; offset=$offset; length=$length) in\n'
+ '${testRegion} in\n' '${testTargets.join('\n')}');
+ }
+
+ void assertHasOperatorRegion(String regionSearch, int regionLength,
+ String targetSearch, int targetLength) {
+ assertHasRegion(regionSearch, regionLength);
+ assertHasTarget(targetSearch, targetLength);
+ }
+
+ /**
+ * Validates that there is a region at the offset of [search] in [testFile].
+ * If [length] is not specified explicitly, then length of an identifier
+ * from [search] is used.
+ */
+ void assertHasRegion(String search, [int length = -1]) {
+ int offset = findOffset(search);
+ if (length == -1) {
+ length = findIdentifierLength(search);
+ }
+ findRegion(offset, length, true);
+ }
+
+ /**
+ * Validates that there is a region at the offset of [search] in [testFile]
+ * with the given [length] or the length of [search].
+ */
+ void assertHasRegionString(String search, [int length = -1]) {
+ int offset = findOffset(search);
+ if (length == -1) {
+ length = search.length;
+ }
+ findRegion(offset, length, true);
+ }
+
+ /**
+ * Validates that there is an identifier region at [regionSearch] with target
+ * at [targetSearch].
+ */
+ void assertHasRegionTarget(String regionSearch, String targetSearch) {
+ assertHasRegion(regionSearch);
+ assertHasTarget(targetSearch);
+ }
+
+ /**
+ * Validates that there is a target in [testTargets] with [testFile], at the
+ * offset of [search] in [testFile], and with the given [length] or the length
+ * of an leading identifier in [search].
+ */
+ void assertHasTarget(String search, [int length = -1]) {
+ int offset = findOffset(search);
+ if (length == -1) {
+ length = findIdentifierLength(search);
+ }
+ assertHasFileTarget(testFile, offset, length);
+ }
+
+ /**
+ * Validates that there is no a region at [search] and with the given
+ * [length].
+ */
+ void assertNoRegion(String search, int length) {
+ int offset = findOffset(search);
+ findRegion(offset, length, false);
+ }
+
+ /**
+ * Validates that there is no a region at [search] with any length.
+ */
+ void assertNoRegionAt(String search) {
+ int offset = findOffset(search);
+ findRegion(offset, -1, false);
+ }
+
+ /**
+ * Validates that there is no a region for [search] string.
+ */
+ void assertNoRegionString(String search) {
+ int offset = findOffset(search);
+ int length = search.length;
+ findRegion(offset, length, false);
+ }
+
+ void assertRegionsSorted() {
+ int lastEnd = -1;
+ for (NavigationRegion region in regions) {
+ int offset = region.offset;
+ if (offset < lastEnd) {
+ fail('$lastEnd was expected to be > $offset in\n' + regions.join('\n'));
+ }
+ lastEnd = offset + region.length;
+ }
+ }
+
+ /**
+ * Finds the navigation region with the given [offset] and [length].
+ * If [length] is `-1`, then it is ignored.
+ *
+ * If [exists] is `true`, then fails if such region does not exist.
+ * Otherwise remembers this it into [testRegion].
+ * Also fills [testTargets] with its targets.
+ *
+ * If [exists] is `false`, then fails if such region exists.
+ */
+ void findRegion(int offset, int length, bool exists) {
+ for (NavigationRegion region in regions) {
+ if (region.offset == offset &&
+ (length == -1 || region.length == length)) {
+ if (exists == false) {
+ fail('Not expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
+ }
+ testRegion = region;
+ testTargetIndexes = region.targets;
+ return;
+ }
+ }
+ if (exists == true) {
+ fail('Expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
+ }
+ }
+}
+
@reflectiveTest
class AnalysisNotificationNavigationTest extends AbstractNavigationTest {
Future prepareNavigation() {
@@ -295,6 +444,23 @@
});
}
+ test_inComment() async {
+ addTestFile('''
+class FirstClass {}
+class SecondClass {
+ /**
+ * Return a [FirstClass] object equivalent to this object in every other way.
+ */
+ convert() {
+ return new FirstClass();
+ }
+}
+''');
+ await prepareNavigation();
+ assertHasRegionTarget('FirstClass]', 'FirstClass {');
+ assertHasRegionTarget('FirstClass(', 'FirstClass {');
+ }
+
test_instanceCreation_implicit() {
addTestFile('''
class A {
@@ -638,152 +804,3 @@
});
}
}
-
-class AbstractNavigationTest extends AbstractAnalysisTest {
- List<NavigationRegion> regions;
- List<NavigationTarget> targets;
- List<String> targetFiles;
-
- NavigationRegion testRegion;
- List<int> testTargetIndexes;
- NavigationTarget testTarget;
-
- /**
- * Validates that there is a target in [testTargetIndexes] with [file],
- * at [offset] and with the given [length].
- */
- void assertHasFileTarget(String file, int offset, int length) {
- List<NavigationTarget> testTargets =
- testTargetIndexes.map((int index) => targets[index]).toList();
- for (NavigationTarget target in testTargets) {
- if (targetFiles[target.fileIndex] == file &&
- target.offset == offset &&
- target.length == length) {
- testTarget = target;
- return;
- }
- }
- fail(
- 'Expected to find target (file=$file; offset=$offset; length=$length) in\n'
- '${testRegion} in\n' '${testTargets.join('\n')}');
- }
-
- void assertHasOperatorRegion(String regionSearch, int regionLength,
- String targetSearch, int targetLength) {
- assertHasRegion(regionSearch, regionLength);
- assertHasTarget(targetSearch, targetLength);
- }
-
- /**
- * Validates that there is a region at the offset of [search] in [testFile].
- * If [length] is not specified explicitly, then length of an identifier
- * from [search] is used.
- */
- void assertHasRegion(String search, [int length = -1]) {
- int offset = findOffset(search);
- if (length == -1) {
- length = findIdentifierLength(search);
- }
- findRegion(offset, length, true);
- }
-
- /**
- * Validates that there is a region at the offset of [search] in [testFile]
- * with the given [length] or the length of [search].
- */
- void assertHasRegionString(String search, [int length = -1]) {
- int offset = findOffset(search);
- if (length == -1) {
- length = search.length;
- }
- findRegion(offset, length, true);
- }
-
- /**
- * Validates that there is an identifier region at [regionSearch] with target
- * at [targetSearch].
- */
- void assertHasRegionTarget(String regionSearch, String targetSearch) {
- assertHasRegion(regionSearch);
- assertHasTarget(targetSearch);
- }
-
- /**
- * Validates that there is a target in [testTargets] with [testFile], at the
- * offset of [search] in [testFile], and with the given [length] or the length
- * of an leading identifier in [search].
- */
- void assertHasTarget(String search, [int length = -1]) {
- int offset = findOffset(search);
- if (length == -1) {
- length = findIdentifierLength(search);
- }
- assertHasFileTarget(testFile, offset, length);
- }
-
- /**
- * Validates that there is no a region at [search] and with the given
- * [length].
- */
- void assertNoRegion(String search, int length) {
- int offset = findOffset(search);
- findRegion(offset, length, false);
- }
-
- /**
- * Validates that there is no a region at [search] with any length.
- */
- void assertNoRegionAt(String search) {
- int offset = findOffset(search);
- findRegion(offset, -1, false);
- }
-
- /**
- * Validates that there is no a region for [search] string.
- */
- void assertNoRegionString(String search) {
- int offset = findOffset(search);
- int length = search.length;
- findRegion(offset, length, false);
- }
-
- void assertRegionsSorted() {
- int lastEnd = -1;
- for (NavigationRegion region in regions) {
- int offset = region.offset;
- if (offset < lastEnd) {
- fail('$lastEnd was expected to be > $offset in\n' + regions.join('\n'));
- }
- lastEnd = offset + region.length;
- }
- }
-
- /**
- * Finds the navigation region with the given [offset] and [length].
- * If [length] is `-1`, then it is ignored.
- *
- * If [exists] is `true`, then fails if such region does not exist.
- * Otherwise remembers this it into [testRegion].
- * Also fills [testTargets] with its targets.
- *
- * If [exists] is `false`, then fails if such region exists.
- */
- void findRegion(int offset, int length, bool exists) {
- for (NavigationRegion region in regions) {
- if (region.offset == offset &&
- (length == -1 || region.length == length)) {
- if (exists == false) {
- fail('Not expected to find (offset=$offset; length=$length) in\n'
- '${regions.join('\n')}');
- }
- testRegion = region;
- testTargetIndexes = region.targets;
- return;
- }
- }
- if (exists == true) {
- fail('Expected to find (offset=$offset; length=$length) in\n'
- '${regions.join('\n')}');
- }
- }
-}
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index af43b51..d81f338 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -7,12 +7,9 @@
import 'dart:collection';
import 'package:analysis_server/src/context_manager.dart';
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
-import 'package:analysis_server/uri/resolver_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
-import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
@@ -55,7 +52,9 @@
*/
static const String TEST_NAME = 'test';
- TestContextManager manager;
+ ContextManagerImpl manager;
+
+ TestContextManagerCallbacks callbacks;
MemoryResourceProvider resourceProvider;
@@ -84,14 +83,40 @@
void setUp() {
resourceProvider = new MemoryResourceProvider();
packageMapProvider = new MockPackageMapProvider();
- manager = new TestContextManager(
- resourceProvider, providePackageResolver, packageMapProvider);
+ manager = new ContextManagerImpl(resourceProvider, providePackageResolver,
+ packageMapProvider, InstrumentationService.NULL_SERVICE);
+ callbacks = new TestContextManagerCallbacks(resourceProvider);
+ manager.callbacks = callbacks;
resourceProvider.newFolder(projPath);
- AbstractContextManager.ENABLE_PACKAGESPEC_SUPPORT = true;
+ ContextManagerImpl.ENABLE_PACKAGESPEC_SUPPORT = true;
}
void tearDown() {
- AbstractContextManager.ENABLE_PACKAGESPEC_SUPPORT = false;
+ ContextManagerImpl.ENABLE_PACKAGESPEC_SUPPORT = false;
+ }
+
+ void test_contextsInAnalysisRoot_nestedContext() {
+ String subProjPath = join(projPath, 'subproj');
+ Folder subProjFolder = resourceProvider.newFolder(subProjPath);
+ resourceProvider.newFile(join(subProjPath, 'pubspec.yaml'), 'contents');
+ String subProjFilePath = join(subProjPath, 'file.dart');
+ resourceProvider.newFile(subProjFilePath, 'contents');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Make sure that there really are contexts for both the main project and
+ // the subproject.
+ Folder projFolder = resourceProvider.getFolder(projPath);
+ ContextInfo projContextInfo = manager.getContextInfoFor(projFolder);
+ expect(projContextInfo, isNotNull);
+ expect(projContextInfo.folder, projFolder);
+ ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder);
+ expect(subProjContextInfo, isNotNull);
+ expect(subProjContextInfo.folder, subProjFolder);
+ expect(projContextInfo.context != subProjContextInfo.context, isTrue);
+ // Check that contextsInAnalysisRoot() works.
+ List<AnalysisContext> contexts = manager.contextsInAnalysisRoot(projFolder);
+ expect(contexts, hasLength(2));
+ expect(contexts, contains(projContextInfo.context));
+ expect(contexts, contains(subProjContextInfo.context));
}
test_ignoreFilesInPackagesFolder() {
@@ -103,12 +128,12 @@
resourceProvider.newFile(filePath1, 'contents');
// "packages" files are ignored initially
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextFilePaths[projPath], isEmpty);
+ expect(callbacks.currentContextFilePaths[projPath], isEmpty);
// "packages" files are ignored during watch
String filePath2 = posix.join(projPath, 'packages', 'file2.dart');
resourceProvider.newFile(filePath2, 'contents');
return pumpEventQueue().then((_) {
- expect(manager.currentContextFilePaths[projPath], isEmpty);
+ expect(callbacks.currentContextFilePaths[projPath], isEmpty);
});
}
@@ -125,6 +150,21 @@
expect(manager.isInAnalysisRoot('$excludedFolder/test.dart'), isFalse);
}
+ void test_isInAnalysisRoot_inNestedContext() {
+ String subProjPath = join(projPath, 'subproj');
+ Folder subProjFolder = resourceProvider.newFolder(subProjPath);
+ resourceProvider.newFile(join(subProjPath, 'pubspec.yaml'), 'contents');
+ String subProjFilePath = join(subProjPath, 'file.dart');
+ resourceProvider.newFile(subProjFilePath, 'contents');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Make sure that there really is a context for the subproject.
+ ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder);
+ expect(subProjContextInfo, isNotNull);
+ expect(subProjContextInfo.folder, subProjFolder);
+ // Check that isInAnalysisRoot() works.
+ expect(manager.isInAnalysisRoot(subProjFilePath), isTrue);
+ }
+
void test_isInAnalysisRoot_inRoot() {
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
expect(manager.isInAnalysisRoot('$projPath/test.dart'), isTrue);
@@ -135,98 +175,17 @@
expect(manager.isInAnalysisRoot('/test.dart'), isFalse);
}
- test_refresh_folder_with_packagespec() {
- // create a context with a .packages file
- String packagespecFile = posix.join(projPath, '.packages');
- resourceProvider.newFile(packagespecFile, '');
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toList(), [projPath]);
- manager.now++;
- manager.refresh(null);
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toList(), [projPath]);
- expect(manager.currentContextTimestamps[projPath], manager.now);
- });
- });
- }
-
- test_refresh_folder_with_packagespec_subfolders() {
- // Create a folder with no .packages file, containing two subfolders with
- // .packages files.
- String subdir1Path = posix.join(projPath, 'subdir1');
- String subdir2Path = posix.join(projPath, 'subdir2');
- String packagespec1Path = posix.join(subdir1Path, '.packages');
- String packagespec2Path = posix.join(subdir2Path, '.packages');
- resourceProvider.newFile(packagespec1Path, '');
- resourceProvider.newFile(packagespec2Path, '');
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toSet(),
- [subdir1Path, subdir2Path, projPath].toSet());
- manager.now++;
- manager.refresh(null);
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toSet(),
- [subdir1Path, subdir2Path, projPath].toSet());
- expect(manager.currentContextTimestamps[projPath], manager.now);
- expect(manager.currentContextTimestamps[subdir1Path], manager.now);
- expect(manager.currentContextTimestamps[subdir2Path], manager.now);
- });
- });
- }
-
- test_refresh_folder_with_pubspec() {
- // create a context with a pubspec.yaml file
- String pubspecPath = posix.join(projPath, 'pubspec.yaml');
- resourceProvider.newFile(pubspecPath, 'pubspec');
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toList(), [projPath]);
- manager.now++;
- manager.refresh(null);
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toList(), [projPath]);
- expect(manager.currentContextTimestamps[projPath], manager.now);
- });
- });
- }
-
- test_refresh_folder_with_pubspec_subfolders() {
- // Create a folder with no pubspec.yaml, containing two subfolders with
- // pubspec.yaml files.
- String subdir1Path = posix.join(projPath, 'subdir1');
- String subdir2Path = posix.join(projPath, 'subdir2');
- String pubspec1Path = posix.join(subdir1Path, 'pubspec.yaml');
- String pubspec2Path = posix.join(subdir2Path, 'pubspec.yaml');
- resourceProvider.newFile(pubspec1Path, 'pubspec');
- resourceProvider.newFile(pubspec2Path, 'pubspec');
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toSet(),
- [subdir1Path, subdir2Path, projPath].toSet());
- manager.now++;
- manager.refresh(null);
- return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toSet(),
- [subdir1Path, subdir2Path, projPath].toSet());
- expect(manager.currentContextTimestamps[projPath], manager.now);
- expect(manager.currentContextTimestamps[subdir1Path], manager.now);
- expect(manager.currentContextTimestamps[subdir2Path], manager.now);
- });
- });
- }
-
test_path_filter() async {
// Setup context.
Folder root = resourceProvider.newFolder(projPath);
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextFilePaths[projPath], isEmpty);
+ expect(callbacks.currentContextFilePaths[projPath], isEmpty);
// Set ignore patterns for context.
+ ContextInfo rootInfo = manager.getContextInfoFor(root);
manager.setIgnorePatternsForContext(
- root, ['sdk_ext/**', 'lib/ignoreme.dart']);
+ rootInfo, ['sdk_ext/**', 'lib/ignoreme.dart']);
// Start creating files.
- newFile([projPath, AbstractContextManager.PUBSPEC_NAME]);
+ newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
String libPath = newFolder([projPath, LIB_NAME]);
newFile([libPath, 'main.dart']);
newFile([libPath, 'ignoreme.dart']);
@@ -237,7 +196,8 @@
// Pump event loop so new files are discovered and added to context.
await pumpEventQueue();
// Verify that ignored files were ignored.
- Map<String, int> fileTimestamps = manager.currentContextFilePaths[projPath];
+ Map<String, int> fileTimestamps =
+ callbacks.currentContextFilePaths[projPath];
expect(fileTimestamps, isNotEmpty);
List<String> files = fileTimestamps.keys.toList();
expect(files.length, equals(1));
@@ -263,13 +223,186 @@
// Setup context.
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// Verify that analysis options was parsed and the ignore patterns applied.
- Map<String, int> fileTimestamps = manager.currentContextFilePaths[projPath];
+ Map<String, int> fileTimestamps =
+ callbacks.currentContextFilePaths[projPath];
expect(fileTimestamps, isNotEmpty);
List<String> files = fileTimestamps.keys.toList();
expect(files.length, equals(1));
expect(files[0], equals('/my/proj/lib/main.dart'));
}
+ test_path_filter_child_contexts_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile([libPath, 'pubspec.yaml'], r'''
+name: foobar
+''');
+ String otherLibPath = newFolder([projPath, 'other_lib']);
+ newFile([otherLibPath, 'entry.dart']);
+ newFile([otherLibPath, 'pubspec.yaml'], r'''
+name: other_lib
+''');
+ // Setup analysis options file with ignore list that ignores the 'other_lib'
+ // directory by name.
+ newFile([projPath, '.analysis_options'], r'''
+analyzer:
+ exclude:
+ - 'other_lib'
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that the context in other_lib wasn't created and that the
+ // context in lib was created.
+ var contexts = manager.contextsInAnalysisRoot(
+ resourceProvider.newFolder(projPath));
+ expect(contexts.length, 2);
+ expect(contexts[0].name, equals('/my/proj'));
+ expect(contexts[1].name, equals('/my/proj/lib'));
+ }
+
+ test_path_filter_wildcard_child_contexts_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile([libPath, 'pubspec.yaml'], r'''
+name: foobar
+''');
+ String otherLibPath = newFolder([projPath, 'other_lib']);
+ newFile([otherLibPath, 'entry.dart']);
+ newFile([otherLibPath, 'pubspec.yaml'], r'''
+name: other_lib
+''');
+ // Setup analysis options file with ignore list that ignores 'other_lib'
+ // and all immediate children.
+ newFile([projPath, '.analysis_options'], r'''
+analyzer:
+ exclude:
+ - 'other_lib/*'
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that the context in other_lib wasn't created and that the
+ // context in lib was created.
+ var contexts = manager.contextsInAnalysisRoot(
+ resourceProvider.newFolder(projPath));
+ expect(contexts.length, 2);
+ expect(contexts[0].name, equals('/my/proj'));
+ expect(contexts[1].name, equals('/my/proj/lib'));
+ }
+
+ test_path_filter_recursive_wildcard_child_contexts_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile([libPath, 'pubspec.yaml'], r'''
+ name: foobar
+ ''');
+ String otherLibPath = newFolder([projPath, 'other_lib']);
+ newFile([otherLibPath, 'entry.dart']);
+ newFile([otherLibPath, 'pubspec.yaml'], r'''
+ name: other_lib
+ ''');
+ // Setup analysis options file with ignore list that ignores 'other_lib'
+ // and all descendants.
+ newFile([projPath, '.analysis_options'], r'''
+analyzer:
+ exclude:
+ - 'other_lib/**'
+ ''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that the context in other_lib wasn't created and that the
+ // context in lib was created.
+ var contexts = manager.contextsInAnalysisRoot(
+ resourceProvider.newFolder(projPath));
+ expect(contexts.length, 2);
+ expect(contexts[0].name, equals('/my/proj'));
+ expect(contexts[1].name, equals('/my/proj/lib'));
+ }
+
+ test_refresh_folder_with_packagespec() {
+ // create a context with a .packages file
+ String packagespecFile = posix.join(projPath, '.packages');
+ resourceProvider.newFile(packagespecFile, '');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toList(), [projPath]);
+ callbacks.now++;
+ manager.refresh(null);
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toList(), [projPath]);
+ expect(callbacks.currentContextTimestamps[projPath], callbacks.now);
+ });
+ });
+ }
+
+ test_refresh_folder_with_packagespec_subfolders() {
+ // Create a folder with no .packages file, containing two subfolders with
+ // .packages files.
+ String subdir1Path = posix.join(projPath, 'subdir1');
+ String subdir2Path = posix.join(projPath, 'subdir2');
+ String packagespec1Path = posix.join(subdir1Path, '.packages');
+ String packagespec2Path = posix.join(subdir2Path, '.packages');
+ resourceProvider.newFile(packagespec1Path, '');
+ resourceProvider.newFile(packagespec2Path, '');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toSet(),
+ [subdir1Path, subdir2Path, projPath].toSet());
+ callbacks.now++;
+ manager.refresh(null);
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toSet(),
+ [subdir1Path, subdir2Path, projPath].toSet());
+ expect(callbacks.currentContextTimestamps[projPath], callbacks.now);
+ expect(callbacks.currentContextTimestamps[subdir1Path], callbacks.now);
+ expect(callbacks.currentContextTimestamps[subdir2Path], callbacks.now);
+ });
+ });
+ }
+
+ test_refresh_folder_with_pubspec() {
+ // create a context with a pubspec.yaml file
+ String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+ resourceProvider.newFile(pubspecPath, 'pubspec');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toList(), [projPath]);
+ callbacks.now++;
+ manager.refresh(null);
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toList(), [projPath]);
+ expect(callbacks.currentContextTimestamps[projPath], callbacks.now);
+ });
+ });
+ }
+
+ test_refresh_folder_with_pubspec_subfolders() {
+ // Create a folder with no pubspec.yaml, containing two subfolders with
+ // pubspec.yaml files.
+ String subdir1Path = posix.join(projPath, 'subdir1');
+ String subdir2Path = posix.join(projPath, 'subdir2');
+ String pubspec1Path = posix.join(subdir1Path, 'pubspec.yaml');
+ String pubspec2Path = posix.join(subdir2Path, 'pubspec.yaml');
+ resourceProvider.newFile(pubspec1Path, 'pubspec');
+ resourceProvider.newFile(pubspec2Path, 'pubspec');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toSet(),
+ [subdir1Path, subdir2Path, projPath].toSet());
+ callbacks.now++;
+ manager.refresh(null);
+ return pumpEventQueue().then((_) {
+ expect(callbacks.currentContextPaths.toSet(),
+ [subdir1Path, subdir2Path, projPath].toSet());
+ expect(callbacks.currentContextTimestamps[projPath], callbacks.now);
+ expect(callbacks.currentContextTimestamps[subdir1Path], callbacks.now);
+ expect(callbacks.currentContextTimestamps[subdir2Path], callbacks.now);
+ });
+ });
+ }
+
test_refresh_oneContext() {
// create two contexts with pubspec.yaml files
String pubspecPath = posix.join(projPath, 'pubspec.yaml');
@@ -283,14 +416,14 @@
List<String> roots = <String>[projPath, proj2Path];
manager.setRoots(roots, <String>[], <String, String>{});
return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toList(), unorderedEquals(roots));
- int then = manager.now;
- manager.now++;
+ expect(callbacks.currentContextPaths.toList(), unorderedEquals(roots));
+ int then = callbacks.now;
+ callbacks.now++;
manager.refresh([resourceProvider.getResource(proj2Path)]);
return pumpEventQueue().then((_) {
- expect(manager.currentContextPaths.toList(), unorderedEquals(roots));
- expect(manager.currentContextTimestamps[projPath], then);
- expect(manager.currentContextTimestamps[proj2Path], manager.now);
+ expect(callbacks.currentContextPaths.toList(), unorderedEquals(roots));
+ expect(callbacks.currentContextTimestamps[projPath], then);
+ expect(callbacks.currentContextTimestamps[proj2Path], callbacks.now);
});
});
}
@@ -300,7 +433,7 @@
resourceProvider.newFile(filePath, 'contents');
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- var filePaths = manager.currentContextFilePaths[projPath];
+ var filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
List<AnalysisContext> contextsInAnalysisRoot =
@@ -318,7 +451,7 @@
resourceProvider.newFile(filePath, 'contents');
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- var filePaths = manager.currentContextFilePaths[projPath];
+ var filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
}
@@ -328,7 +461,7 @@
resourceProvider.newDummyLink(filePath);
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- var filePaths = manager.currentContextFilePaths[projPath];
+ var filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, isEmpty);
}
@@ -336,9 +469,9 @@
String examplePath = newFolder([projPath, EXAMPLE_NAME]);
String libPath = newFolder([projPath, LIB_NAME]);
- newFile([projPath, AbstractContextManager.PACKAGE_SPEC_NAME]);
+ newFile([projPath, ContextManagerImpl.PACKAGE_SPEC_NAME]);
newFile([libPath, 'main.dart']);
- newFile([examplePath, AbstractContextManager.PACKAGE_SPEC_NAME]);
+ newFile([examplePath, ContextManagerImpl.PACKAGE_SPEC_NAME]);
newFile([examplePath, 'example.dart']);
packageMapProvider.packageMap['proj'] =
@@ -346,15 +479,15 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, hasLength(2));
- expect(manager.currentContextPaths, contains(projPath));
- Set<Source> projSources = manager.currentContextSources[projPath];
+ expect(callbacks.currentContextPaths, contains(projPath));
+ Set<Source> projSources = callbacks.currentContextSources[projPath];
expect(projSources, hasLength(1));
expect(projSources.first.uri.toString(), 'file:///my/proj/lib/main.dart');
- expect(manager.currentContextPaths, contains(examplePath));
- Set<Source> exampleSources = manager.currentContextSources[examplePath];
+ expect(callbacks.currentContextPaths, contains(examplePath));
+ Set<Source> exampleSources = callbacks.currentContextSources[examplePath];
expect(exampleSources, hasLength(1));
expect(exampleSources.first.uri.toString(),
'file:///my/proj/example/example.dart');
@@ -364,9 +497,9 @@
String examplePath = newFolder([projPath, EXAMPLE_NAME]);
String libPath = newFolder([projPath, LIB_NAME]);
- newFile([projPath, AbstractContextManager.PUBSPEC_NAME]);
+ newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
newFile([libPath, 'main.dart']);
- newFile([examplePath, AbstractContextManager.PUBSPEC_NAME]);
+ newFile([examplePath, ContextManagerImpl.PUBSPEC_NAME]);
newFile([examplePath, 'example.dart']);
packageMapProvider.packageMap['proj'] =
@@ -374,15 +507,15 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, hasLength(2));
- expect(manager.currentContextPaths, contains(projPath));
- Set<Source> projSources = manager.currentContextSources[projPath];
+ expect(callbacks.currentContextPaths, contains(projPath));
+ Set<Source> projSources = callbacks.currentContextSources[projPath];
expect(projSources, hasLength(1));
expect(projSources.first.uri.toString(), 'package:proj/main.dart');
- expect(manager.currentContextPaths, contains(examplePath));
- Set<Source> exampleSources = manager.currentContextSources[examplePath];
+ expect(callbacks.currentContextPaths, contains(examplePath));
+ Set<Source> exampleSources = callbacks.currentContextSources[examplePath];
expect(exampleSources, hasLength(1));
expect(exampleSources.first.uri.toString(),
'file:///my/proj/example/example.dart');
@@ -392,9 +525,9 @@
packageMapProvider.packageMap = null;
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- expect(manager.currentContextPaths, hasLength(1));
- expect(manager.currentContextPaths, contains(projPath));
- expect(manager.currentContextFilePaths[projPath], hasLength(0));
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, contains(projPath));
+ expect(callbacks.currentContextFilePaths[projPath], hasLength(0));
}
void test_setRoots_addFolderWithPackagespec() {
@@ -409,12 +542,12 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- expect(manager.currentContextPaths, hasLength(1));
- expect(manager.currentContextPaths, contains(projPath));
- expect(manager.currentContextFilePaths[projPath], hasLength(1));
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, contains(projPath));
+ expect(callbacks.currentContextFilePaths[projPath], hasLength(1));
// smoketest resolution
- SourceFactory sourceFactory = manager.currentContext.sourceFactory;
+ SourceFactory sourceFactory = callbacks.currentContext.sourceFactory;
Source resolvedSource =
sourceFactory.resolveUri(source, 'package:unittest/unittest.dart');
expect(resolvedSource, isNotNull);
@@ -427,9 +560,9 @@
resourceProvider.newFile(pubspecPath, 'pubspec');
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- expect(manager.currentContextPaths, hasLength(1));
- expect(manager.currentContextPaths, contains(projPath));
- expect(manager.currentContextFilePaths[projPath], hasLength(0));
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, contains(projPath));
+ expect(callbacks.currentContextFilePaths[projPath], hasLength(0));
}
void test_setRoots_addFolderWithPubspec_andPackagespec() {
@@ -439,7 +572,7 @@
resourceProvider.newFile(packagespecPath, '');
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// verify
- manager.assertContextPaths([projPath]);
+ callbacks.assertContextPaths([projPath]);
}
void test_setRoots_addFolderWithPubspecAndLib() {
@@ -448,7 +581,7 @@
String srcPath = newFolder([libPath, SRC_NAME]);
String testPath = newFolder([projPath, TEST_NAME]);
- newFile([projPath, AbstractContextManager.PUBSPEC_NAME]);
+ newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
String appPath = newFile([binPath, 'app.dart']);
newFile([libPath, 'main.dart']);
newFile([srcPath, 'internal.dart']);
@@ -458,10 +591,10 @@
[resourceProvider.getResource(libPath)];
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- Set<Source> sources = manager.currentContextSources[projPath];
+ Set<Source> sources = callbacks.currentContextSources[projPath];
- expect(manager.currentContextPaths, hasLength(1));
- expect(manager.currentContextPaths, contains(projPath));
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, contains(projPath));
expect(sources, hasLength(4));
List<String> uris =
sources.map((Source source) => source.uri.toString()).toList();
@@ -491,11 +624,11 @@
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProjectA, subProjectB]);
+ callbacks.assertContextPaths([root, subProjectA, subProjectB]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProjectA, [subProjectA_file]);
- manager.assertContextFiles(subProjectB, [subProjectB_file]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
+ callbacks.assertContextFiles(subProjectB, [subProjectB_file]);
}
void test_setRoots_addFolderWithPubspecFolders() {
@@ -519,11 +652,11 @@
};
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProjectA, subProjectB]);
+ callbacks.assertContextPaths([root, subProjectA, subProjectB]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProjectA, [subProjectA_file]);
- manager.assertContextFiles(subProjectB, [subProjectB_file]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
+ callbacks.assertContextFiles(subProjectB, [subProjectB_file]);
// verify package maps
_checkPackageMap(root, isNull);
_checkPackageMap(
@@ -572,8 +705,8 @@
resourceProvider.newFile(file2, '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file1], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file2]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file2]);
}
void test_setRoots_exclude_newRoot_withExcludedFolder() {
@@ -588,8 +721,8 @@
resourceProvider.newFile(fileB, 'library b;');
// set roots
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_exclude_sameRoot_addExcludedFile() {
@@ -602,12 +735,12 @@
resourceProvider.newFile(file2, '// 2');
// set roots
manager.setRoots(<String>[project], <String>[], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file1, file2]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1, file2]);
// exclude "2"
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file1]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
}
void test_setRoots_exclude_sameRoot_addExcludedFolder() {
@@ -622,12 +755,12 @@
resourceProvider.newFile(fileB, 'library b;');
// initially both "aaa/a" and "bbb/b" are included
manager.setRoots(<String>[project], <String>[], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA, fileB]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA, fileB]);
// exclude "bbb/"
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFile() {
@@ -640,12 +773,12 @@
resourceProvider.newFile(file2, '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file1]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
// stop excluding "2"
manager.setRoots(<String>[project], <String>[], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file1, file2]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1, file2]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFile_inFolder() {
@@ -658,12 +791,12 @@
resourceProvider.newFile(file2, '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file1]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1]);
// stop excluding "2"
manager.setRoots(<String>[project], <String>[], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [file1, file2]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [file1, file2]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFolder() {
@@ -678,12 +811,12 @@
resourceProvider.newFile(fileB, 'library b;');
// exclude "bbb/"
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
// stop excluding "bbb/"
manager.setRoots(<String>[project], <String>[], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA, fileB]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA, fileB]);
}
void test_setRoots_newFolderWithPackageRoot() {
@@ -723,11 +856,11 @@
packageMapProvider.packageMap = null;
// add one root - there is a context
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, hasLength(1));
// set empty roots - no contexts
manager.setRoots(<String>[], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(0));
- expect(manager.currentContextFilePaths, hasLength(0));
+ expect(callbacks.currentContextPaths, hasLength(0));
+ expect(callbacks.currentContextFilePaths, hasLength(0));
}
void test_setRoots_removeFolderWithPackagespec() {
@@ -736,11 +869,11 @@
resourceProvider.newFile(pubspecPath, '');
// add one root - there is a context
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, hasLength(1));
// set empty roots - no contexts
manager.setRoots(<String>[], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(0));
- expect(manager.currentContextFilePaths, hasLength(0));
+ expect(callbacks.currentContextPaths, hasLength(0));
+ expect(callbacks.currentContextFilePaths, hasLength(0));
}
void test_setRoots_removeFolderWithPackagespecFolder() {
@@ -765,16 +898,17 @@
// set roots
manager.setRoots(
<String>[projectA, projectB], <String>[], <String, String>{});
- manager.assertContextPaths([projectA, subProjectA, projectB, subProjectB]);
- manager.assertContextFiles(projectA, [projectA_file]);
- manager.assertContextFiles(projectB, [projectB_file]);
- manager.assertContextFiles(subProjectA, [subProjectA_file]);
- manager.assertContextFiles(subProjectB, [subProjectB_file]);
+ callbacks
+ .assertContextPaths([projectA, subProjectA, projectB, subProjectB]);
+ callbacks.assertContextFiles(projectA, [projectA_file]);
+ callbacks.assertContextFiles(projectB, [projectB_file]);
+ callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
+ callbacks.assertContextFiles(subProjectB, [subProjectB_file]);
// remove "projectB"
manager.setRoots(<String>[projectA], <String>[], <String, String>{});
- manager.assertContextPaths([projectA, subProjectA]);
- manager.assertContextFiles(projectA, [projectA_file]);
- manager.assertContextFiles(subProjectA, [subProjectA_file]);
+ callbacks.assertContextPaths([projectA, subProjectA]);
+ callbacks.assertContextFiles(projectA, [projectA_file]);
+ callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
}
void test_setRoots_removeFolderWithPubspec() {
@@ -783,11 +917,11 @@
resourceProvider.newFile(pubspecPath, 'pubspec');
// add one root - there is a context
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, hasLength(1));
// set empty roots - no contexts
manager.setRoots(<String>[], <String>[], <String, String>{});
- expect(manager.currentContextPaths, hasLength(0));
- expect(manager.currentContextFilePaths, hasLength(0));
+ expect(callbacks.currentContextPaths, hasLength(0));
+ expect(callbacks.currentContextFilePaths, hasLength(0));
}
void test_setRoots_removeFolderWithPubspecFolder() {
@@ -812,16 +946,17 @@
// set roots
manager.setRoots(
<String>[projectA, projectB], <String>[], <String, String>{});
- manager.assertContextPaths([projectA, subProjectA, projectB, subProjectB]);
- manager.assertContextFiles(projectA, [projectA_file]);
- manager.assertContextFiles(projectB, [projectB_file]);
- manager.assertContextFiles(subProjectA, [subProjectA_file]);
- manager.assertContextFiles(subProjectB, [subProjectB_file]);
+ callbacks
+ .assertContextPaths([projectA, subProjectA, projectB, subProjectB]);
+ callbacks.assertContextFiles(projectA, [projectA_file]);
+ callbacks.assertContextFiles(projectB, [projectB_file]);
+ callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
+ callbacks.assertContextFiles(subProjectB, [subProjectB_file]);
// remove "projectB"
manager.setRoots(<String>[projectA], <String>[], <String, String>{});
- manager.assertContextPaths([projectA, subProjectA]);
- manager.assertContextFiles(projectA, [projectA_file]);
- manager.assertContextFiles(subProjectA, [subProjectA_file]);
+ callbacks.assertContextPaths([projectA, subProjectA]);
+ callbacks.assertContextFiles(projectA, [projectA_file]);
+ callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
}
void test_setRoots_removePackageRoot() {
@@ -842,7 +977,7 @@
test_watch_addDummyLink() {
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// empty folder initially
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, isEmpty);
// add link
String filePath = posix.join(projPath, 'foo.dart');
@@ -856,7 +991,7 @@
test_watch_addFile() {
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// empty folder initially
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(0));
// add file
String filePath = posix.join(projPath, 'foo.dart');
@@ -879,20 +1014,20 @@
resourceProvider.newFile(fileA, 'library a;');
// set roots
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
// add a file, ignored as excluded
resourceProvider.newFile(fileB, 'library b;');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([project]);
- manager.assertContextFiles(project, [fileA]);
+ callbacks.assertContextPaths([project]);
+ callbacks.assertContextFiles(project, [fileA]);
});
}
test_watch_addFileInSubfolder() {
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// empty folder initially
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(0));
// add file in subfolder
String filePath = posix.join(projPath, 'foo', 'bar.dart');
@@ -913,14 +1048,14 @@
resourceProvider.newFile(rootFile, 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root]);
+ callbacks.assertContextPaths([root]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(root, [rootFile]);
// add packagespec - still just one root
resourceProvider.newFile(rootPackagespec, '');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile]);
// TODO(pquitslund): verify that a new source factory is created --
// likely this will need to happen in a corresponding ServerContextManagerTest.
});
@@ -938,15 +1073,15 @@
resourceProvider.newFile(subFile, 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root]);
+ callbacks.assertContextPaths([root]);
// verify files
- manager.assertContextFiles(root, [rootFile, subFile]);
+ callbacks.assertContextFiles(root, [rootFile, subFile]);
// add .packages
resourceProvider.newFile(subPubspec, '');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
});
}
@@ -964,15 +1099,15 @@
resourceProvider.newFile(subFile, 'library sub;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
// add pubspec - ignore, because is already in a packagespec-based context
resourceProvider.newFile(subSubPubspec, '');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
});
}
@@ -990,18 +1125,18 @@
resourceProvider.newFile(subFile, 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
+ callbacks.assertContextPaths([root, subProject]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
// add .packages
resourceProvider.newFile(subPackagespec, '');
return pumpEventQueue().then((_) {
// Should NOT create another context.
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
});
}
@@ -1014,14 +1149,14 @@
resourceProvider.newFile(rootFile, 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root]);
+ callbacks.assertContextPaths([root]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(root, [rootFile]);
// add pubspec - still just one root
resourceProvider.newFile(rootPubspec, 'pubspec');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile]);
});
}
@@ -1037,15 +1172,15 @@
resourceProvider.newFile(subFile, 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root]);
+ callbacks.assertContextPaths([root]);
// verify files
- manager.assertContextFiles(root, [rootFile, subFile]);
+ callbacks.assertContextFiles(root, [rootFile, subFile]);
// add pubspec
resourceProvider.newFile(subPubspec, 'pubspec');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
});
}
@@ -1063,15 +1198,15 @@
resourceProvider.newFile(subFile, 'library sub;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
// add pubspec - ignore, because is already in a pubspec-based context
resourceProvider.newFile(subSubPubspec, 'pubspec');
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
});
}
@@ -1082,7 +1217,7 @@
Folder projFolder = file.parent;
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// the file was added
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
expect(file.exists, isTrue);
@@ -1103,7 +1238,7 @@
Folder projFolder = file.parent;
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// the file was added
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
expect(file.exists, isTrue);
@@ -1127,13 +1262,13 @@
resourceProvider.newFile(rootFile, 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile]);
// delete the pubspec
resourceProvider.deleteFile(rootPubspec);
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile]);
});
}
@@ -1150,15 +1285,15 @@
resourceProvider.newFile(subFile, 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
+ callbacks.assertContextPaths([root, subProject]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
// delete the pubspec
resourceProvider.deleteFile(subPubspec);
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile, subFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile, subFile]);
});
}
@@ -1177,16 +1312,16 @@
resourceProvider.newFile(subFile, 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
+ callbacks.assertContextPaths([root, subProject]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
// delete the packagespec
resourceProvider.deleteFile(subPackagespec);
return pumpEventQueue().then((_) {
// Should NOT merge
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextPaths([root, subProject]);
+ callbacks.assertContextFiles(subProject, [subFile]);
});
}
@@ -1200,13 +1335,13 @@
resourceProvider.newFile(rootFile, 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile]);
// delete the pubspec
resourceProvider.deleteFile(rootPubspec);
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile]);
});
}
@@ -1223,15 +1358,15 @@
resourceProvider.newFile(subFile, 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
+ callbacks.assertContextPaths([root, subProject]);
// verify files
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
+ callbacks.assertContextFiles(root, [rootFile]);
+ callbacks.assertContextFiles(subProject, [subFile]);
// delete the pubspec
resourceProvider.deleteFile(subPubspec);
return pumpEventQueue().then((_) {
- manager.assertContextPaths([root]);
- manager.assertContextFiles(root, [rootFile, subFile]);
+ callbacks.assertContextPaths([root]);
+ callbacks.assertContextFiles(root, [rootFile, subFile]);
});
}
@@ -1241,15 +1376,15 @@
resourceProvider.newFile(filePath, 'contents');
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// the file was added
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
- expect(filePaths[filePath], equals(manager.now));
+ expect(filePaths[filePath], equals(callbacks.now));
// update the file
- manager.now++;
+ callbacks.now++;
resourceProvider.modifyFile(filePath, 'new contents');
return pumpEventQueue().then((_) {
- return expect(filePaths[filePath], equals(manager.now));
+ return expect(filePaths[filePath], equals(callbacks.now));
});
}
@@ -1302,70 +1437,6 @@
});
}
- test_watch_modifyPackageMapDependency_outsideProject() {
- // create a dependency file
- String dependencyPath = '/my/other/dep';
- resourceProvider.newFile(dependencyPath, 'contents');
- packageMapProvider.dependencies.add(dependencyPath);
- // create a Dart file
- String dartFilePath = posix.join(projPath, 'main.dart');
- resourceProvider.newFile(dartFilePath, 'contents');
- // the created context has the expected empty package map
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- _checkPackageMap(projPath, isEmpty);
- // configure package map
- String packagePath = '/package/foo';
- resourceProvider.newFolder(packagePath);
- packageMapProvider.packageMap = {'foo': projPath};
- // Changing a .dart file in the project shouldn't cause a new
- // package map to be picked up.
- resourceProvider.modifyFile(dartFilePath, 'new contents');
- return pumpEventQueue().then((_) {
- _checkPackageMap(projPath, isEmpty);
- // However, changing the package map dependency should.
- resourceProvider.modifyFile(dependencyPath, 'new contents');
- return pumpEventQueue().then((_) {
- _checkPackageMap(projPath, equals(packageMapProvider.packageMap));
- });
- });
- }
-
- test_watch_modifyPackageMapDependency_redundantly() async {
- // Create two dependency files
- String dependencyPath1 = posix.join(projPath, 'dep1');
- String dependencyPath2 = posix.join(projPath, 'dep2');
- resourceProvider.newFile(dependencyPath1, 'contents');
- resourceProvider.newFile(dependencyPath2, 'contents');
- packageMapProvider.dependencies.add(dependencyPath1);
- packageMapProvider.dependencies.add(dependencyPath2);
- // Create a dart file
- String dartFilePath = posix.join(projPath, 'main.dart');
- resourceProvider.newFile(dartFilePath, 'contents');
- // Verify that the created context has the expected empty package map.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- _checkPackageMap(projPath, isEmpty);
- expect(packageMapProvider.computeCount, 1);
- // Set up a different package map
- String packagePath = '/package/foo';
- resourceProvider.newFolder(packagePath);
- packageMapProvider.packageMap = {'foo': projPath};
- // Change both dependencies.
- resourceProvider.modifyFile(dependencyPath1, 'new contents');
- resourceProvider.modifyFile(dependencyPath2, 'new contents');
- // Arrange for the next call to computePackageMap to return the correct
- // timestamps for the dependencies.
- packageMapProvider.modificationTimes = <String, int>{};
- for (String path in [dependencyPath1, dependencyPath2]) {
- File resource = resourceProvider.getResource(path);
- packageMapProvider.modificationTimes[path] = resource.modificationStamp;
- }
- // This should cause the new package map to be picked up, by executing
- // computePackageMap just one additional time.
- await pumpEventQueue();
- _checkPackageMap(projPath, equals(packageMapProvider.packageMap));
- expect(packageMapProvider.computeCount, 2);
- }
-
test_watch_modifyPackagespec() {
String packagesPath = '$projPath/.packages';
String filePath = '$projPath/bin/main.dart';
@@ -1375,18 +1446,18 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- Map<String, int> filePaths = manager.currentContextFilePaths[projPath];
+ Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
- Packages packages = manager.currentContextPackagespecs[projPath];
+ Packages packages = callbacks.currentContextDispositions[projPath].packages;
expect(packages.packages, isEmpty);
// update .packages
- manager.now++;
+ callbacks.now++;
resourceProvider.modifyFile(packagesPath, 'main:./lib/');
return pumpEventQueue().then((_) {
// verify new package info
- packages = manager.currentContextPackagespecs[projPath];
+ packages = callbacks.currentContextDispositions[projPath].packages;
expect(packages.packages, unorderedEquals(['main']));
});
}
@@ -1396,9 +1467,9 @@
* using a package map matching [expectation].
*/
void _checkPackageMap(String path, expectation) {
- UriResolver resolver = manager.currentContextPackageUriResolvers[path];
+ FolderDisposition disposition = callbacks.currentContextDispositions[path];
Map<String, List<Folder>> packageMap =
- resolver is PackageMapUriResolver ? resolver.packageMap : null;
+ disposition is PackageMapDisposition ? disposition.packageMap : null;
expect(packageMap, expectation);
}
@@ -1407,14 +1478,14 @@
* using a package root maching [expectation].
*/
void _checkPackageRoot(String path, expectation) {
- UriResolver resolver = manager.currentContextPackageUriResolvers[path];
- expect(resolver, new isInstanceOf<PackageUriResolver>());
- PackageUriResolver packageUriResolver = resolver;
- expect(packageUriResolver.packagesDirectory_forTesting, expectation);
+ FolderDisposition disposition = callbacks.currentContextDispositions[path];
+ expect(disposition.packageRoot, expectation);
+ // TODO(paulberry): we should also verify that the package map itself is
+ // correct. See dartbug.com/23909.
}
}
-class TestContextManager extends AbstractContextManager {
+class TestContextManagerCallbacks extends ContextManagerCallbacks {
/**
* Source of timestamps stored in [currentContextFilePaths].
*/
@@ -1444,21 +1515,17 @@
};
/**
- * Map from context to package URI resolver.
+ * Map from context to folder disposition.
*/
- final Map<String, UriResolver> currentContextPackageUriResolvers =
- <String, UriResolver>{};
+ final Map<String, FolderDisposition> currentContextDispositions =
+ <String, FolderDisposition>{};
/**
- * Map from context to packages object.
+ * Resource provider used for this test.
*/
- final Map<String, Packages> currentContextPackagespecs = <String, Packages>{};
+ final ResourceProvider resourceProvider;
- TestContextManager(MemoryResourceProvider resourceProvider,
- ResolverProvider packageResolverProvider,
- OptimizingPubPackageMapProvider packageMapProvider)
- : super(resourceProvider, packageResolverProvider, packageMapProvider,
- InstrumentationService.NULL_SERVICE);
+ TestContextManagerCallbacks(this.resourceProvider);
/**
* Iterable of the paths to contexts that currently exist.
@@ -1466,21 +1533,18 @@
Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
@override
- AnalysisContext addContext(
- Folder folder, UriResolver packageUriResolver, Packages packages) {
+ AnalysisContext addContext(Folder folder, FolderDisposition disposition) {
String path = folder.path;
expect(currentContextPaths, isNot(contains(path)));
currentContextTimestamps[path] = now;
currentContextFilePaths[path] = <String, int>{};
currentContextSources[path] = new HashSet<Source>();
- currentContextPackageUriResolvers[path] = packageUriResolver;
- currentContextPackagespecs[path] = packages;
+ currentContextDispositions[path] = disposition;
currentContext = AnalysisEngine.instance.createAnalysisContext();
List<UriResolver> resolvers = [new FileUriResolver()];
- if (packageUriResolver != null) {
- resolvers.add(packageUriResolver);
- }
- currentContext.sourceFactory = new SourceFactory(resolvers, packages);
+ resolvers.addAll(disposition.createPackageUriResolvers(resourceProvider));
+ currentContext.sourceFactory =
+ new SourceFactory(resolvers, disposition.packages);
return currentContext;
}
@@ -1517,13 +1581,13 @@
}
@override
- void removeContext(Folder folder) {
+ void removeContext(Folder folder, List<String> flushedFiles) {
String path = folder.path;
expect(currentContextPaths, contains(path));
currentContextTimestamps.remove(path);
currentContextFilePaths.remove(path);
currentContextSources.remove(path);
- currentContextPackageUriResolvers.remove(path);
+ currentContextDispositions.remove(path);
}
@override
@@ -1542,9 +1606,8 @@
@override
void updateContextPackageUriResolver(
- Folder contextFolder, UriResolver packageUriResolver, Packages packages) {
- currentContextPackageUriResolvers[contextFolder.path] = packageUriResolver;
- currentContextPackagespecs[contextFolder.path] = packages;
+ Folder contextFolder, FolderDisposition disposition) {
+ currentContextDispositions[contextFolder.path] = disposition;
}
}
@@ -1564,7 +1627,7 @@
TestUriResolver(this.uriMap);
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
return uriMap[uri];
}
}
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 63cd20f..08916ce 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -21,9 +21,9 @@
import 'package:analysis_server/src/services/index/index.dart' show Index;
import 'package:analysis_server/src/services/index/local_memory_index.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -657,7 +657,7 @@
Test_AnalysisServer(ServerCommunicationChannel channel,
ResourceProvider resourceProvider,
- OptimizingPubPackageMapProvider packageMapProvider, Index index,
+ PubPackageMapProvider packageMapProvider, Index index,
ServerPlugin serverPlugin, AnalysisServerOptions analysisServerOptions,
DartSdk defaultSdk, InstrumentationService instrumentationService)
: super(channel, resourceProvider, packageMapProvider, index,
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index 8fa9234..2ff54e1 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/domain_execution.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
import 'package:analysis_server/src/protocol.dart';
@@ -225,7 +226,7 @@
when(context.getLibrariesReferencedFromHtml(anyObject))
.thenReturn([source6, source7]);
- ServerContextManager manager = new ServerContextManagerMock();
+ ContextManager manager = new ServerContextManagerMock();
when(manager.isInAnalysisRoot(anyString)).thenReturn(true);
AnalysisServer server = new AnalysisServerMock();
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
new file mode 100644
index 0000000..e4402ef
--- /dev/null
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -0,0 +1,149 @@
+// 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.edit.organize_directives;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/edit/edit_domain.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:plugin/manager.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart' hide ERROR;
+
+import '../analysis_abstract.dart';
+import '../mocks.dart';
+
+main() {
+ groupSep = ' | ';
+ defineReflectiveTests(OrganizeDirectivesTest);
+}
+
+@reflectiveTest
+class OrganizeDirectivesTest extends AbstractAnalysisTest {
+ SourceFileEdit fileEdit;
+
+ @override
+ void setUp() {
+ super.setUp();
+ createProject();
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins([server.serverPlugin]);
+ handler = new EditDomainHandler(server);
+ }
+
+ Future test_BAD_doesNotExist() async {
+ await waitForTasksFinished();
+ Request request =
+ new EditOrganizeDirectivesParams('/no/such/file.dart').toRequest('0');
+ Response response = handler.handleRequest(request);
+ expect(
+ response, isResponseFailure('0', RequestErrorCode.FILE_NOT_ANALYZED));
+ }
+
+ Future test_BAD_hasParseError() async {
+ addTestFile('''
+import 'dart:async'
+
+main() {}
+''');
+ await waitForTasksFinished();
+ Request request = new EditOrganizeDirectivesParams(testFile).toRequest('0');
+ Response response = handler.handleRequest(request);
+ expect(response,
+ isResponseFailure('0', RequestErrorCode.ORGANIZE_DIRECTIVES_ERROR));
+ }
+
+ Future test_BAD_notDartFile() async {
+ await waitForTasksFinished();
+ Request request =
+ new EditOrganizeDirectivesParams('/not-a-Dart-file.txt').toRequest('0');
+ Response response = handler.handleRequest(request);
+ expect(
+ response, isResponseFailure('0', RequestErrorCode.FILE_NOT_ANALYZED));
+ }
+
+ Future test_OK_remove_unresolvedDirectives() {
+ addFile('$testFolder/existing_part1.dart', 'part of lib;');
+ addFile('$testFolder/existing_part2.dart', 'part of lib;');
+ addTestFile('''
+library lib;
+
+export 'dart:noSuchExportSdkLibrary';
+export 'dart:async';
+export 'package:noSuchExportPackage/andLib.dart';
+export 'dart:math';
+
+import 'dart:async';
+import 'dart:noSuchImportSdkLibrary';
+import 'dart:math';
+import 'package:noSuchImportPackage/andLib.dart';
+
+part 'existing_part1.dart';
+part 'no_such_part.dart';
+part 'existing_part2.dart';
+
+main(Future f) {
+ print(PI);
+}
+''');
+ return _assertOrganized(r'''
+library lib;
+
+import 'dart:async';
+import 'dart:math';
+
+export 'dart:async';
+export 'dart:math';
+
+part 'existing_part1.dart';
+part 'existing_part2.dart';
+
+main(Future f) {
+ print(PI);
+}
+''');
+ }
+
+ Future test_OK_remove_unusedImports() {
+ addTestFile('''
+library lib;
+
+import 'dart:async';
+import 'dart:math';
+import 'dart:convert';
+import 'dart:collection';
+
+main() {
+ print(PI);
+ new HashMap();
+}
+''');
+ return _assertOrganized(r'''
+library lib;
+
+import 'dart:collection';
+import 'dart:math';
+
+main() {
+ print(PI);
+ new HashMap();
+}
+''');
+ }
+
+ Future _assertOrganized(String expectedCode) async {
+ await waitForTasksFinished();
+ _requestOrganize();
+ String resultCode = SourceEdit.applySequence(testCode, fileEdit.edits);
+ expect(resultCode, expectedCode);
+ }
+
+ void _requestOrganize() {
+ Request request = new EditOrganizeDirectivesParams(testFile).toRequest('0');
+ Response response = handleSuccessfulRequest(request);
+ var result = new EditOrganizeDirectivesResult.fromResponse(response);
+ fileEdit = result.edit;
+ }
+}
diff --git a/pkg/analysis_server/test/edit/sort_members_test.dart b/pkg/analysis_server/test/edit/sort_members_test.dart
index 6aa638c..194baa9 100644
--- a/pkg/analysis_server/test/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/edit/sort_members_test.dart
@@ -33,38 +33,35 @@
handler = new EditDomainHandler(server);
}
- Future test_BAD_doesNotExist() {
- return waitForTasksFinished().then((_) {
- Request request =
- new EditSortMembersParams('/no/such/file.dart').toRequest('0');
- Response response = handler.handleRequest(request);
- expect(response,
- isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
- });
+ Future test_BAD_doesNotExist() async {
+ await waitForTasksFinished();
+ Request request =
+ new EditSortMembersParams('/no/such/file.dart').toRequest('0');
+ Response response = handler.handleRequest(request);
+ expect(response,
+ isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
}
- Future test_BAD_hasParseError() {
+ Future test_BAD_hasParseError() async {
addTestFile('''
main() {
print()
}
''');
- return waitForTasksFinished().then((_) {
- Request request = new EditSortMembersParams(testFile).toRequest('0');
- Response response = handler.handleRequest(request);
- expect(response,
- isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS));
- });
+ await waitForTasksFinished();
+ Request request = new EditSortMembersParams(testFile).toRequest('0');
+ Response response = handler.handleRequest(request);
+ expect(response,
+ isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS));
}
- Future test_BAD_notDartFile() {
- return waitForTasksFinished().then((_) {
- Request request =
- new EditSortMembersParams('/not-a-Dart-file.txt').toRequest('0');
- Response response = handler.handleRequest(request);
- expect(response,
- isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
- });
+ Future test_BAD_notDartFile() async {
+ await waitForTasksFinished();
+ Request request =
+ new EditSortMembersParams('/not-a-Dart-file.txt').toRequest('0');
+ Response response = handler.handleRequest(request);
+ expect(response,
+ isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
}
Future test_OK_classMembers_method() {
@@ -148,12 +145,11 @@
''');
}
- Future _assertSorted(String expectedCode) {
- return waitForTasksFinished().then((_) {
- _requestSort();
- String resultCode = SourceEdit.applySequence(testCode, fileEdit.edits);
- expect(resultCode, expectedCode);
- });
+ Future _assertSorted(String expectedCode) async {
+ await waitForTasksFinished();
+ _requestSort();
+ String resultCode = SourceEdit.applySequence(testCode, fileEdit.edits);
+ expect(resultCode, expectedCode);
}
void _requestSort() {
diff --git a/pkg/analysis_server/test/edit/test_all.dart b/pkg/analysis_server/test/edit/test_all.dart
index 40e83f1..e9a9ea1 100644
--- a/pkg/analysis_server/test/edit/test_all.dart
+++ b/pkg/analysis_server/test/edit/test_all.dart
@@ -9,6 +9,7 @@
import 'assists_test.dart' as assists_test;
import 'fixes_test.dart' as fixes_test;
import 'format_test.dart' as format_test;
+import 'organize_directives_test.dart' as organize_directives_test;
import 'refactoring_test.dart' as refactoring_test;
import 'sort_members_test.dart' as sort_members_test;
@@ -21,6 +22,7 @@
assists_test.main();
fixes_test.main();
format_test.main();
+ organize_directives_test.main();
refactoring_test.main();
sort_members_test.main();
});
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 4da1b0c..8f3915e 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -1390,6 +1390,39 @@
}
/**
+ * Organizes all of the directives - removes unused imports and sorts
+ * directives of the given Dart file according to the Dart Style Guide.
+ *
+ * If a request is made for a file that does not exist, does not belong to an
+ * analysis root or is not a Dart file, FILE_NOT_ANALYZED will be generated.
+ *
+ * If directives of the Dart file cannot be organized, for example because it
+ * has scan or parse errors, or by other reasons, ORGANIZE_DIRECTIVES_ERROR
+ * will be generated. The message will provide datails about the reason.
+ *
+ * Parameters
+ *
+ * file ( FilePath )
+ *
+ * The Dart file to organize directives in.
+ *
+ * Returns
+ *
+ * edit ( SourceFileEdit )
+ *
+ * The file edit that is to be applied to the given file to effect the
+ * organizing.
+ */
+ Future<EditOrganizeDirectivesResult> sendEditOrganizeDirectives(String file) {
+ var params = new EditOrganizeDirectivesParams(file).toJson();
+ return server.send("edit.organizeDirectives", params)
+ .then((result) {
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditOrganizeDirectivesResult.fromJson(decoder, 'result', result);
+ });
+ }
+
+ /**
* Create an execution context for the executable file with the given path.
* The context that is created will persist until execution.deleteContext is
* used to delete it. Clients, therefore, are responsible for managing the
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index f46b338..3345554 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -16,6 +16,7 @@
import 'integration_test_methods.dart';
import 'protocol_matchers.dart';
+import 'package:analysis_server/src/server/driver.dart' as analysisServer;
const Matcher isBool = const isInstanceOf<bool>('bool');
@@ -590,7 +591,8 @@
* "--pause-isolates-on-exit", allowing the observatory to be used.
*/
Future start({bool debugServer: false, int diagnosticPort,
- bool profileServer: false, bool useAnalysisHighlight2: false}) {
+ bool profileServer: false, bool newTaskModel: false,
+ bool useAnalysisHighlight2: false}) {
if (_process != null) {
throw new Exception('Process already started');
}
@@ -619,6 +621,9 @@
if (useAnalysisHighlight2) {
arguments.add('--useAnalysisHighlight2');
}
+ if (newTaskModel) {
+ arguments.add('--${analysisServer.Driver.ENABLE_NEW_TASK_MODEL}');
+ }
return Process.start(dartBinary, arguments).then((Process process) {
_process = process;
process.exitCode.then((int code) {
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 0a5ae19..24cc21e 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -853,6 +853,30 @@
}));
/**
+ * edit.organizeDirectives params
+ *
+ * {
+ * "file": FilePath
+ * }
+ */
+final Matcher isEditOrganizeDirectivesParams = new LazyMatcher(() => new MatchesJsonObject(
+ "edit.organizeDirectives params", {
+ "file": isFilePath
+ }));
+
+/**
+ * edit.organizeDirectives result
+ *
+ * {
+ * "edit": SourceFileEdit
+ * }
+ */
+final Matcher isEditOrganizeDirectivesResult = new LazyMatcher(() => new MatchesJsonObject(
+ "edit.organizeDirectives result", {
+ "edit": isSourceFileEdit
+ }));
+
+/**
* execution.createContext params
*
* {
@@ -1936,6 +1960,7 @@
*
* enum {
* CONTENT_MODIFIED
+ * FILE_NOT_ANALYZED
* FORMAT_INVALID_FILE
* FORMAT_WITH_ERRORS
* GET_ERRORS_INVALID_FILE
@@ -1946,6 +1971,7 @@
* INVALID_PARAMETER
* INVALID_REQUEST
* NO_INDEX_GENERATED
+ * ORGANIZE_DIRECTIVES_ERROR
* REFACTORING_REQUEST_CANCELLED
* SERVER_ALREADY_STARTED
* SERVER_ERROR
@@ -1959,6 +1985,7 @@
*/
final Matcher isRequestErrorCode = new MatchesEnum("RequestErrorCode", [
"CONTENT_MODIFIED",
+ "FILE_NOT_ANALYZED",
"FORMAT_INVALID_FILE",
"FORMAT_WITH_ERRORS",
"GET_ERRORS_INVALID_FILE",
@@ -1969,6 +1996,7 @@
"INVALID_PARAMETER",
"INVALID_REQUEST",
"NO_INDEX_GENERATED",
+ "ORGANIZE_DIRECTIVES_ERROR",
"REFACTORING_REQUEST_CANCELLED",
"SERVER_ALREADY_STARTED",
"SERVER_ERROR",
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 1aa8f47..3358b47 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -4,20 +4,20 @@
library mocks;
-@MirrorsUsed(targets: 'mocks', override: '*')
-import 'dart:mirrors';
import 'dart:async';
import 'dart:io';
+@MirrorsUsed(targets: 'mocks', override: '*')
+import 'dart:mirrors';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/channel/channel.dart';
import 'package:analysis_server/src/operation/operation.dart';
import 'package:analysis_server/src/operation/operation_analysis.dart';
import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind;
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
import 'package:analyzer/file_system/file_system.dart' as resource;
import 'package:analyzer/file_system/memory_file_system.dart' as resource;
import 'package:analyzer/source/package_map_provider.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -152,7 +152,7 @@
/**
* A mock [PackageMapProvider].
*/
-class MockPackageMapProvider implements OptimizingPubPackageMapProvider {
+class MockPackageMapProvider implements PubPackageMapProvider {
/**
* Package map that will be returned by the next call to [computePackageMap].
*/
@@ -170,36 +170,17 @@
Set<String> dependencies = new Set<String>();
/**
- * Modification times that will be returned by the next call to
- * [computePackageMap]. This will be filtered to include only those paths
- * mentioned in the `dependencies` field of [computePackageMap]'s
- * `previousInfo` argument.
- */
- Map<String, int> modificationTimes = <String, int>{};
-
- /**
* Number of times [computePackageMap] has been called.
*/
int computeCount = 0;
@override
- OptimizingPubPackageMapInfo computePackageMap(resource.Folder folder,
- [OptimizingPubPackageMapInfo previousInfo]) {
+ PackageMapInfo computePackageMap(resource.Folder folder) {
++computeCount;
- Map<String, int> filteredModificationTimes = <String, int>{};
- if (previousInfo != null) {
- for (String dependency in previousInfo.dependencies) {
- if (modificationTimes.containsKey(dependency)) {
- filteredModificationTimes[dependency] = modificationTimes[dependency];
- }
- }
- }
if (packageMaps != null) {
- return new OptimizingPubPackageMapInfo(
- packageMaps[folder.path], dependencies, filteredModificationTimes);
+ return new PackageMapInfo(packageMaps[folder.path], dependencies);
}
- return new OptimizingPubPackageMapInfo(
- packageMap, dependencies, filteredModificationTimes);
+ return new PackageMapInfo(packageMap, dependencies);
}
noSuchMethod(Invocation invocation) {
diff --git a/pkg/analysis_server/test/operation/operation_queue_test.dart b/pkg/analysis_server/test/operation/operation_queue_test.dart
index 71569e8..47f0bcf 100644
--- a/pkg/analysis_server/test/operation/operation_queue_test.dart
+++ b/pkg/analysis_server/test/operation/operation_queue_test.dart
@@ -5,6 +5,7 @@
library test.operation.queue;
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/operation/operation.dart';
import 'package:analysis_server/src/operation/operation_analysis.dart';
import 'package:analysis_server/src/operation/operation_queue.dart';
@@ -39,7 +40,6 @@
}
class AnalysisServerMock extends TypedMock implements AnalysisServer {
-
@override
final ResourceProvider resourceProvider;
@@ -51,8 +51,7 @@
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
-class ServerContextManagerMock extends TypedMock
- implements ServerContextManager {
+class ServerContextManagerMock extends TypedMock implements ContextManager {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analysis_server/test/server_options_test.dart b/pkg/analysis_server/test/server_options_test.dart
new file mode 100644
index 0000000..f3a3790
--- /dev/null
+++ b/pkg/analysis_server/test/server_options_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library analysis_server.test.server_options;
+
+import 'package:analysis_server/src/server_options.dart';
+import 'package:unittest/unittest.dart';
+
+void main() {
+ groupSep = ' | ';
+
+ group('server_options', () {
+ test('basic - []', () {
+ var options = new ServerOptions.fromContents('''# ignored
+foo: bar
+baz: padded
+''');
+ expect(options['foo'], equals('bar'));
+ expect(options['baz'], equals('padded'));
+ });
+ test('basic - isSet', () {
+ var options = new ServerOptions.fromContents('''foo: true
+bar: TRUE
+baz: false
+foobar: off
+''');
+ expect(options.isSet('foo'), isTrue);
+ expect(options.isSet('bar'), isTrue);
+ expect(options.isSet('baz'), isFalse);
+ expect(options.isSet('foobar'), isFalse);
+ expect(options.isSet('does_not_exist'), isFalse);
+ expect(options.isSet('does_not_exist', defaultValue: true), isTrue);
+ });
+
+ test('basic - getStringValue', () {
+ var options = new ServerOptions.fromContents('''foo: someValue
+''');
+ expect(options.getStringValue('foo'), equals('someValue'));
+ expect(options.getStringValue('not_there'), isNull);
+ expect(options.getStringValue('not_there', defaultValue: 'bar'),
+ equals('bar'));
+ });
+ });
+}
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index 57fb4e9..072f97c 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -498,6 +498,30 @@
assertTarget('zoo', 'zoo(z) {}');
}
+ test_SwitchStatement_c() {
+ // Token('c') SwitchStatement
+ addTestSource('main() { switch(x) {c^} }');
+ assertTarget('}', 'switch (x) {}');
+ }
+
+ test_SwitchStatement_c2() {
+ // Token('c') SwitchStatement
+ addTestSource('main() { switch(x) { c^ } }');
+ assertTarget('}', 'switch (x) {}');
+ }
+
+ test_SwitchStatement_empty() {
+ // SwitchStatement
+ addTestSource('main() { switch(x) {^} }');
+ assertTarget('}', 'switch (x) {}');
+ }
+
+ test_SwitchStatement_empty2() {
+ // SwitchStatement
+ addTestSource('main() { switch(x) { ^ } }');
+ assertTarget('}', 'switch (x) {}');
+ }
+
test_TypeArgumentList() {
// TypeName TypeArgumentList TypeName
addTestSource('main() { C<^> c; }');
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index 249e1c0..6bcbce1 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -115,7 +115,7 @@
{CompletionSuggestionKind csKind: CompletionSuggestionKind.INVOCATION,
int relevance: DART_RELEVANCE_DEFAULT, String importUri,
protocol.ElementKind elemKind: null, bool isDeprecated: false,
- bool isPotential: false}) {
+ bool isPotential: false, String elemFile, int elemOffset}) {
CompletionSuggestion cs =
getSuggest(completion: completion, csKind: csKind, elemKind: elemKind);
if (cs == null) {
@@ -133,18 +133,34 @@
expect(cs.selectionLength, equals(0));
expect(cs.isDeprecated, equals(isDeprecated));
expect(cs.isPotential, equals(isPotential));
+ if (cs.element != null) {
+ expect(cs.element.location, isNotNull);
+ expect(cs.element.location.file, isNotNull);
+ expect(cs.element.location.offset, isNotNull);
+ expect(cs.element.location.length, isNotNull);
+ expect(cs.element.location.startColumn, isNotNull);
+ expect(cs.element.location.startLine, isNotNull);
+ }
+ if (elemFile != null) {
+ expect(cs.element.location.file, elemFile);
+ }
+ if (elemOffset != null) {
+ expect(cs.element.location.offset, elemOffset);
+ }
return cs;
}
CompletionSuggestion assertSuggestClass(String name,
{int relevance: DART_RELEVANCE_DEFAULT, String importUri,
CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- bool isDeprecated: false}) {
+ bool isDeprecated: false, String elemFile, int elemOffset}) {
CompletionSuggestion cs = assertSuggest(name,
csKind: kind,
relevance: relevance,
importUri: importUri,
- isDeprecated: isDeprecated);
+ isDeprecated: isDeprecated,
+ elemFile: elemFile,
+ elemOffset: elemOffset);
protocol.Element element = cs.element;
expect(element, isNotNull);
expect(element.kind, equals(protocol.ElementKind.CLASS));
@@ -171,9 +187,10 @@
}
CompletionSuggestion assertSuggestConstructor(String name,
- {int relevance: DART_RELEVANCE_DEFAULT, String importUri}) {
- CompletionSuggestion cs =
- assertSuggest(name, relevance: relevance, importUri: importUri);
+ {int relevance: DART_RELEVANCE_DEFAULT, String importUri,
+ int elemOffset}) {
+ CompletionSuggestion cs = assertSuggest(name,
+ relevance: relevance, importUri: importUri, elemOffset: elemOffset);
protocol.Element element = cs.element;
expect(element, isNotNull);
expect(element.kind, equals(protocol.ElementKind.CONSTRUCTOR));
@@ -573,7 +590,8 @@
CompletionSuggestion assertSuggestImportedClass(String name,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- int relevance: DART_RELEVANCE_DEFAULT, String importUri}) {
+ int relevance: DART_RELEVANCE_DEFAULT, String importUri,
+ String elemFile}) {
return assertNotSuggested(name);
}
@@ -683,7 +701,8 @@
CompletionSuggestion assertSuggestLocalClass(String name,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false,
+ String elemFile, int elemOffset}) {
return assertNotSuggested(name);
}
@@ -692,7 +711,8 @@
return assertNotSuggested(name);
}
- CompletionSuggestion assertSuggestLocalConstructor(String name) {
+ CompletionSuggestion assertSuggestLocalConstructor(String name,
+ {int elemOffset}) {
return assertNotSuggested(name);
}
@@ -1249,7 +1269,7 @@
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestLocalClass('X');
+ assertSuggestLocalClass('X', elemFile: testFile);
assertSuggestLocalClass('Z');
assertSuggestLocalMethod('a', 'X', null);
assertSuggestLocalMethod('b', 'X', 'void');
@@ -1260,7 +1280,7 @@
assertNotSuggested('x');
assertNotSuggested('partT8');
- assertSuggestImportedClass('A');
+ assertSuggestImportedClass('A', elemFile: '/testAB.dart');
assertNotSuggested('_B');
assertSuggestImportedClass('C');
assertNotSuggested('partBoo');
@@ -1945,7 +1965,7 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestLocalClass('A');
+ assertSuggestLocalClass('A', elemOffset: 6);
assertSuggestImportedClass('Object');
assertNotSuggested('x');
});
@@ -3986,6 +4006,35 @@
});
}
+ test_SwitchStatement_c() {
+ // SwitchStatement Block BlockFunctionBody MethodDeclaration
+ addTestSource('class A {String g(int x) {switch(x) {c^}}}');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_SwitchStatement_case() {
+ // SwitchStatement Block BlockFunctionBody MethodDeclaration
+ addTestSource('class A {String g(int x) {switch(x) {case 0: ^}}}');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestLocalClass('A');
+ assertSuggestLocalMethod('g', 'A', 'String');
+ assertSuggestImportedClass('String');
+ });
+ }
+
+ test_SwitchStatement_empty() {
+ // SwitchStatement Block BlockFunctionBody MethodDeclaration
+ addTestSource('class A {String g(int x) {switch(x) {^}}}');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
test_ThisExpression_block() {
// MethodInvocation ExpressionStatement Block
addTestSource('''
diff --git a/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
index c33ec14..42a32cd 100644
--- a/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
@@ -125,9 +125,13 @@
@override
CompletionSuggestion assertSuggestImportedClass(String name,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- int relevance: DART_RELEVANCE_DEFAULT, String importUri}) {
+ int relevance: DART_RELEVANCE_DEFAULT, String importUri,
+ String elemFile}) {
return assertSuggestClass(name,
- relevance: relevance, kind: kind, importUri: importUri);
+ relevance: relevance,
+ kind: kind,
+ importUri: importUri,
+ elemFile: elemFile);
}
@override
diff --git a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
index c9666b1..6db5b89 100644
--- a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
@@ -1128,6 +1128,33 @@
relevance: DART_RELEVANCE_HIGH);
}
+ test_switch_start5() {
+ addTestSource('main() {switch(1) {c^ default:}}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
+ relevance: DART_RELEVANCE_HIGH);
+ expect(request.replacementOffset, 19);
+ expect(request.replacementLength, 1);
+ }
+
+ test_switch_start6() {
+ addTestSource('main() {switch(1) {c^}}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
+ relevance: DART_RELEVANCE_HIGH);
+ expect(request.replacementOffset, 19);
+ expect(request.replacementLength, 1);
+ }
+
+ test_switch_start7() {
+ addTestSource('main() {switch(1) { c^ }}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
+ relevance: DART_RELEVANCE_HIGH);
+ expect(request.replacementOffset, 20);
+ expect(request.replacementLength, 1);
+ }
+
test_switch_statement() {
addTestSource('main() {switch(1) {case 1:^}}');
expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
index e46a771..36310da 100644
--- a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
@@ -24,9 +24,14 @@
@override
CompletionSuggestion assertSuggestLocalClass(String name,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false,
+ String elemFile, int elemOffset}) {
return assertSuggestClass(name,
- kind: kind, relevance: relevance, isDeprecated: isDeprecated);
+ elemFile: elemFile,
+ elemOffset: elemOffset,
+ isDeprecated: isDeprecated,
+ kind: kind,
+ relevance: relevance);
}
@override
@@ -36,8 +41,9 @@
}
@override
- CompletionSuggestion assertSuggestLocalConstructor(String name) {
- return assertSuggestConstructor(name);
+ CompletionSuggestion assertSuggestLocalConstructor(String name,
+ {int elemOffset}) {
+ return assertSuggestConstructor(name, elemOffset: elemOffset);
}
@override
@@ -602,7 +608,7 @@
return computeFull((bool result) {
CompletionSuggestion suggestion;
- suggestion = assertSuggestLocalConstructor('A');
+ suggestion = assertSuggestLocalConstructor('A', elemOffset: -1);
expect(suggestion.element.parameters, '()');
expect(suggestion.element.returnType, 'A');
expect(suggestion.declaringType, 'A');
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index 27e32b7..04ce497 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -1124,19 +1124,72 @@
assertOpType(typeNames: true);
}
- test_SwitchCase() {
- // SimpleIdentifier SwitchCase SwitchStatement
- addTestSource('''m() {switch (x) {case ^D: return;}}''');
- // TODO (danrubel) should refine this to return constants
+ test_SwitchCase_before() {
+ // SwitchCase SwitchStatement Block
+ addTestSource('main() {switch(k) {^case 1:}}');
+ assertOpType();
+ }
+
+ test_SwitchCase_between() {
+ // SwitchCase SwitchStatement Block
+ addTestSource('main() {switch(k) {case 1: ^ case 2: return}}');
assertOpType(returnValue: true, typeNames: true, voidReturn: true);
}
- test_SwitchStatement() {
+ test_SwitchCase_expression1() {
+ // SimpleIdentifier SwitchCase SwitchStatement
+ addTestSource('''m() {switch (x) {case ^D: return;}}''');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_SwitchCase_expression2() {
+ // SimpleIdentifier SwitchCase SwitchStatement
+ addTestSource('''m() {switch (x) {case ^}}''');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_SwitchDefault_before() {
+ // SwitchDefault SwitchStatement Block
+ addTestSource('main() {switch(k) { ^ default: return;}}');
+ assertOpType();
+ }
+
+ test_SwitchDefault_between() {
+ // SwitchDefault SwitchStatement Block
+ addTestSource('main() {switch(k) {case 1: ^ default: return;}}');
+ assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+ }
+
+ test_SwitchStatement_body_empty() {
+ // Token('}') SwitchStatement Block
+ addTestSource('main() {switch(k) {^}}');
+ assertOpType();
+ }
+
+ test_SwitchStatement_body_end() {
+ // Token('}') SwitchStatement Block
+ addTestSource('main() {switch(k) {case 1:^}}');
+ assertOpType(returnValue: true, typeNames: true, voidReturn: true);
+ }
+
+ test_SwitchStatement_expression1() {
// SimpleIdentifier SwitchStatement Block
addTestSource('main() {switch(^k) {case 1:{}}}');
assertOpType(returnValue: true, typeNames: true);
}
+ test_SwitchStatement_expression2() {
+ // SimpleIdentifier SwitchStatement Block
+ addTestSource('main() {switch(k^) {case 1:{}}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_SwitchStatement_expression_empty() {
+ // SimpleIdentifier SwitchStatement Block
+ addTestSource('main() {switch(^) {case 1:{}}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
test_ThisExpression_block() {
// MethodInvocation ExpressionStatement Block
addTestSource('''
diff --git a/pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart b/pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart
index 7e77a87..7778869 100644
--- a/pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart
@@ -238,7 +238,18 @@
addTestSource('import "dart:async" deferred as bar; foo() {bar.^}');
return computeFull((bool result) {
assertSuggestClass('Future');
- assertSuggestFunction('loadLibrary', 'void');
+ assertSuggestFunction('loadLibrary', 'Future<dynamic>');
+ });
+ }
+
+ test_libraryPrefix_with_exports() {
+ addSource('/libA.dart', 'library libA; class A { }');
+ addSource('/libB.dart', 'library libB; export "/libA.dart"; class B { }');
+ addTestSource('import "/libB.dart" as foo; main() {foo.^} class C { }');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestClass('B');
+ assertSuggestClass('A');
});
}
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 8e27fa5..e1c9f62 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -106,7 +106,9 @@
}
void test_addTypeAnnotation_BAD_privateType_closureParameter() {
- addSource('/my_lib.dart', '''
+ addSource(
+ '/my_lib.dart',
+ '''
library my_lib;
class A {}
class _B extends A {}
@@ -122,7 +124,9 @@
}
void test_addTypeAnnotation_BAD_privateType_declaredIdentifier() {
- addSource('/my_lib.dart', '''
+ addSource(
+ '/my_lib.dart',
+ '''
library my_lib;
class A {}
class _B extends A {}
@@ -141,7 +145,9 @@
}
void test_addTypeAnnotation_BAD_privateType_list() {
- addSource('/my_lib.dart', '''
+ addSource(
+ '/my_lib.dart',
+ '''
library my_lib;
class A {}
class _B extends A {}
@@ -157,7 +163,9 @@
}
void test_addTypeAnnotation_BAD_privateType_variable() {
- addSource('/my_lib.dart', '''
+ addSource(
+ '/my_lib.dart',
+ '''
library my_lib;
class A {}
class _B extends A {}
@@ -178,7 +186,10 @@
final f = 0;
}
''');
- assertHasAssistAt('final ', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'final ',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class A {
final int f = 0;
}
@@ -191,7 +202,10 @@
var f = 0;
}
''');
- assertHasAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'var ',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class A {
int f = 0;
}
@@ -239,7 +253,10 @@
}
}
''');
- assertHasAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'item in',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class A<T> {
main(List<List<T>> items) {
for (List<T> item in items) {
@@ -257,14 +274,20 @@
}
''');
// on identifier
- assertHasAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'item in',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main(List<String> items) {
for (String item in items) {
}
}
''');
// on "for"
- assertHasAssistAt('for (', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'for (',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main(List<String> items) {
for (String item in items) {
}
@@ -273,7 +296,9 @@
}
void test_addTypeAnnotation_declaredIdentifier_OK_addImport_dartUri() {
- addSource('/my_lib.dart', r'''
+ addSource(
+ '/my_lib.dart',
+ r'''
import 'dart:async';
List<Future<int>> getFutures() => null;
''');
@@ -284,7 +309,10 @@
}
}
''');
- assertHasAssistAt('future in', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'future in',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
import 'my_lib.dart';
import 'dart:async';
main() {
@@ -301,7 +329,10 @@
}
}
''');
- assertHasAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'item in',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main(List<String> items) {
for (final String item in items) {
}
@@ -317,7 +348,10 @@
}
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class A {
main(List<int> items) {
List<int> v = items;
@@ -334,7 +368,10 @@
}
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class A<T> {
main(List<T> items) {
List<T> v = items;
@@ -344,7 +381,9 @@
}
void test_addTypeAnnotation_local_OK_addImport_dartUri() {
- addSource('/my_lib.dart', r'''
+ addSource(
+ '/my_lib.dart',
+ r'''
import 'dart:async';
Future<int> getFutureInt() => null;
''');
@@ -354,7 +393,10 @@
var v = getFutureInt();
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
import 'my_lib.dart';
import 'dart:async';
main() {
@@ -365,7 +407,9 @@
void test_addTypeAnnotation_local_OK_addImport_notLibraryUnit() {
// prepare library
- addSource('/my_lib.dart', r'''
+ addSource(
+ '/my_lib.dart',
+ r'''
import 'dart:async';
Future<int> getFutureInt() => null;
''');
@@ -398,7 +442,9 @@
{
var testFileEdit = change.getFileEdit('/app.dart');
var resultCode = SourceEdit.applySequence(appCode, testFileEdit.edits);
- expect(resultCode, '''
+ expect(
+ resultCode,
+ '''
library my_app;
import 'my_lib.dart';
import 'dart:async';
@@ -408,7 +454,9 @@
{
var testFileEdit = change.getFileEdit('/test.dart');
var resultCode = SourceEdit.applySequence(testCode, testFileEdit.edits);
- expect(resultCode, '''
+ expect(
+ resultCode,
+ '''
part of my_app;
main() {
Future<int> v = getFutureInt();
@@ -418,10 +466,14 @@
}
void test_addTypeAnnotation_local_OK_addImport_relUri() {
- addSource('/aa/bbb/lib_a.dart', r'''
+ addSource(
+ '/aa/bbb/lib_a.dart',
+ r'''
class MyClass {}
''');
- addSource('/ccc/lib_b.dart', r'''
+ addSource(
+ '/ccc/lib_b.dart',
+ r'''
import '../aa/bbb/lib_a.dart';
MyClass newMyClass() => null;
''');
@@ -431,7 +483,10 @@
var v = newMyClass();
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
import 'ccc/lib_b.dart';
import 'aa/bbb/lib_a.dart';
main() {
@@ -446,7 +501,10 @@
var v = () => 1;
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
Function v = () => 1;
}
@@ -459,7 +517,10 @@
var v = 0;
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
int v = 0;
}
@@ -472,7 +533,10 @@
var v = <String>[];
}
''');
- assertHasAssistAt('v =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
List<String> v = <String>[];
}
@@ -487,7 +551,10 @@
var x = f();
}
''');
- assertHasAssistAt('x =', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'x =',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class C {}
C f() => null;
main() {
@@ -502,7 +569,10 @@
var v = 123;
}
''');
- assertHasAssistAt('23', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ '23',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
int v = 123;
}
@@ -515,7 +585,10 @@
var abc = 0;
}
''');
- assertHasAssistAt('bc', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'bc',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
int abc = 0;
}
@@ -528,7 +601,10 @@
var v = 0;
}
''');
- assertHasAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'var ',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
int v = 0;
}
@@ -541,7 +617,10 @@
var v = 123; // marker
}
''');
- assertHasAssistAt(' // marker', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ ' // marker',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
main() {
int v = 123; // marker
}
@@ -603,7 +682,10 @@
var v = getValue();
}
''');
- assertHasAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'var ',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
class _A {}
_A getValue() => new _A();
main() {
@@ -639,7 +721,10 @@
foo((test) {});
}
''');
- assertHasAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'test',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
foo(f(int p)) {}
main() {
foo((int test) {});
@@ -651,7 +736,10 @@
resolveTestUnit('''
var V = 0;
''');
- assertHasAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'var ',
+ DartAssistKind.ADD_TYPE_ANNOTATION,
+ '''
int V = 0;
''');
}
@@ -678,7 +766,9 @@
}
List<int> readBytes() => <int>[];
''');
- assertHasAssistAt('readBytes();', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE,
+ assertHasAssistAt(
+ 'readBytes();',
+ DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE,
'''
main() {
List<int> bytes;
@@ -686,10 +776,11 @@
}
List<int> readBytes() => <int>[];
''');
- _assertLinkedGroup(change.linkedEditGroups[0], [
- 'readBytes = '
- ], expectedSuggestions(
- LinkedEditSuggestionKind.VARIABLE, ['list', 'bytes2', 'readBytes']));
+ _assertLinkedGroup(
+ change.linkedEditGroups[0],
+ ['readBytes = '],
+ expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
+ ['list', 'bytes2', 'readBytes']));
}
void test_assignToLocalVariable_alreadyAssignment() {
@@ -735,17 +826,52 @@
resolveTestUnit('''
setup(x) {}
main() {
- setup(() => print('done'));
+ setup(() => 42);
}
''');
- assertHasAssistAt('() => print', DartAssistKind.CONVERT_INTO_BLOCK_BODY, '''
+ assertHasAssistAt(
+ '() => 42',
+ DartAssistKind.CONVERT_INTO_BLOCK_BODY,
+ '''
setup(x) {}
main() {
setup(() {
- return print('done');
+ return 42;
});
}
''');
+ {
+ Position exitPos = change.selection;
+ expect(exitPos, isNotNull);
+ expect(exitPos.file, testFile);
+ expect(exitPos.offset - 3, resultCode.indexOf('42;'));
+ }
+ }
+
+ void test_convertToBlockBody_OK_closure_voidExpression() {
+ resolveTestUnit('''
+setup(x) {}
+main() {
+ setup(() => print('done'));
+}
+''');
+ assertHasAssistAt(
+ '() => print',
+ DartAssistKind.CONVERT_INTO_BLOCK_BODY,
+ '''
+setup(x) {}
+main() {
+ setup(() {
+ print('done');
+ });
+}
+''');
+ {
+ Position exitPos = change.selection;
+ expect(exitPos, isNotNull);
+ expect(exitPos.file, testFile);
+ expect(exitPos.offset - 3, resultCode.indexOf("');"));
+ }
}
void test_convertToBlockBody_OK_constructor() {
@@ -754,7 +880,10 @@
factory A() => null;
}
''');
- assertHasAssistAt('A()', DartAssistKind.CONVERT_INTO_BLOCK_BODY, '''
+ assertHasAssistAt(
+ 'A()',
+ DartAssistKind.CONVERT_INTO_BLOCK_BODY,
+ '''
class A {
factory A() {
return null;
@@ -769,7 +898,10 @@
mmm() => 123;
}
''');
- assertHasAssistAt('mmm()', DartAssistKind.CONVERT_INTO_BLOCK_BODY, '''
+ assertHasAssistAt(
+ 'mmm()',
+ DartAssistKind.CONVERT_INTO_BLOCK_BODY,
+ '''
class A {
mmm() {
return 123;
@@ -782,7 +914,10 @@
resolveTestUnit('''
fff() => 123;
''');
- assertHasAssistAt('fff()', DartAssistKind.CONVERT_INTO_BLOCK_BODY, '''
+ assertHasAssistAt(
+ 'fff()',
+ DartAssistKind.CONVERT_INTO_BLOCK_BODY,
+ '''
fff() {
return 123;
}
@@ -793,7 +928,10 @@
resolveTestUnit('''
fff() => 123;
''');
- assertHasAssistAt('23;', DartAssistKind.CONVERT_INTO_BLOCK_BODY, '''
+ assertHasAssistAt(
+ '23;',
+ DartAssistKind.CONVERT_INTO_BLOCK_BODY,
+ '''
fff() {
return 123;
}
@@ -825,7 +963,10 @@
});
}
''');
- assertHasAssistAt('42;', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, '''
+ assertHasAssistAt(
+ '42;',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
setup(x) {}
main() {
setup(() => 42);
@@ -833,6 +974,26 @@
''');
}
+ void test_convertToExpressionBody_OK_closure_voidExpression() {
+ resolveTestUnit('''
+setup(x) {}
+main() {
+ setup(() {
+ print('test');
+ });
+}
+''');
+ assertHasAssistAt(
+ 'print(',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
+setup(x) {}
+main() {
+ setup(() => print('test'));
+}
+''');
+ }
+
void test_convertToExpressionBody_OK_constructor() {
resolveTestUnit('''
class A {
@@ -841,7 +1002,10 @@
}
}
''');
- assertHasAssistAt('A()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, '''
+ assertHasAssistAt(
+ 'A()',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
class A {
factory A() => null;
}
@@ -854,7 +1018,10 @@
return 42;
}
''');
- assertHasAssistAt('{', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, '''
+ assertHasAssistAt(
+ '{',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
fff() => 42;
''');
}
@@ -865,7 +1032,10 @@
return 42;
}
''');
- assertHasAssistAt('ff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, '''
+ assertHasAssistAt(
+ 'ff()',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
fff() => 42;
''');
}
@@ -878,8 +1048,10 @@
}
}
''');
- assertHasAssistAt('{ // marker',
- DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, '''
+ assertHasAssistAt(
+ '{ // marker',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
class A {
m() => 42;
}
@@ -892,7 +1064,10 @@
return 42;
}
''');
- assertHasAssistAt('return', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, '''
+ assertHasAssistAt(
+ 'return',
+ DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
+ '''
fff() => 42;
''');
}
@@ -968,7 +1143,10 @@
A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
}
''');
- assertHasAssistAt('aaa, ', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+ assertHasAssistAt(
+ 'aaa, ',
+ DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
+ '''
class A {
double aaa2;
int bbb2;
@@ -985,7 +1163,10 @@
}
}
''');
- assertHasAssistAt('test {', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+ assertHasAssistAt(
+ 'test {',
+ DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
+ '''
class A {
int test2;
A(this.test2) {
@@ -1002,7 +1183,10 @@
}
}
''');
- assertHasAssistAt('test)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+ assertHasAssistAt(
+ 'test)',
+ DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
+ '''
class A {
int test;
A(this.test) {
@@ -1019,7 +1203,10 @@
A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
}
''');
- assertHasAssistAt('bbb)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+ assertHasAssistAt(
+ 'bbb)',
+ DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
+ '''
class A {
double aaa2;
int bbb2;
@@ -1091,7 +1278,10 @@
}
}
''');
- assertHasAssistAt('item in', DartAssistKind.CONVERT_INTO_FOR_INDEX, '''
+ assertHasAssistAt(
+ 'item in',
+ DartAssistKind.CONVERT_INTO_FOR_INDEX,
+ '''
main(List<String> items) {
for (int i = 0; i < items.length; i++) {
String item = items[i];
@@ -1109,7 +1299,10 @@
}
}
''');
- assertHasAssistAt('tring item', DartAssistKind.CONVERT_INTO_FOR_INDEX, '''
+ assertHasAssistAt(
+ 'tring item',
+ DartAssistKind.CONVERT_INTO_FOR_INDEX,
+ '''
main(List<String> items) {
for (int i = 0; i < items.length; i++) {
String item = items[i];
@@ -1127,7 +1320,10 @@
}
}
''');
- assertHasAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX, '''
+ assertHasAssistAt(
+ 'for (String',
+ DartAssistKind.CONVERT_INTO_FOR_INDEX,
+ '''
main(List<String> items) {
for (int i = 0; i < items.length; i++) {
String item = items[i];
@@ -1145,7 +1341,10 @@
}
}
''');
- assertHasAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX, '''
+ assertHasAssistAt(
+ 'for (String',
+ DartAssistKind.CONVERT_INTO_FOR_INDEX,
+ '''
main(List<String> items) {
for (int j = 0; j < items.length; j++) {
String item = items[j];
@@ -1164,7 +1363,10 @@
}
}
''');
- assertHasAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX, '''
+ assertHasAssistAt(
+ 'for (String',
+ DartAssistKind.CONVERT_INTO_FOR_INDEX,
+ '''
main(List<String> items) {
for (int k = 0; k < items.length; k++) {
String item = items[k];
@@ -1181,7 +1383,10 @@
!(p is String);
}
''');
- assertHasAssistAt('p is', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ 'p is',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
p is! String;
}
@@ -1194,7 +1399,10 @@
!(p is String);
}
''');
- assertHasAssistAt('String)', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ 'String)',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
p is! String;
}
@@ -1207,7 +1415,10 @@
!(p is String);
}
''');
- assertHasAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ 'is String',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
p is! String;
}
@@ -1220,7 +1431,10 @@
!!(p is String);
}
''');
- assertHasAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ 'is String',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
!(p is! String);
}
@@ -1233,7 +1447,10 @@
!!(p is String);
}
''');
- assertHasAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ '!(p',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
!(p is! String);
}
@@ -1246,7 +1463,10 @@
!(p is String);
}
''');
- assertHasAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ '!(p',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
p is! String;
}
@@ -1259,7 +1479,10 @@
!(p is String);
}
''');
- assertHasAssistAt('(p is', DartAssistKind.CONVERT_INTO_IS_NOT, '''
+ assertHasAssistAt(
+ '(p is',
+ DartAssistKind.CONVERT_INTO_IS_NOT,
+ '''
main(p) {
p is! String;
}
@@ -1355,7 +1578,10 @@
!str.isEmpty;
}
''');
- assertHasAssistAt('isEmpty', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY, '''
+ assertHasAssistAt(
+ 'isEmpty',
+ DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
+ '''
main(String str) {
str.isNotEmpty;
}
@@ -1368,7 +1594,10 @@
!str.isEmpty;
}
''');
- assertHasAssistAt('str.', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY, '''
+ assertHasAssistAt(
+ 'str.',
+ DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
+ '''
main(String str) {
str.isNotEmpty;
}
@@ -1381,7 +1610,10 @@
!'text'.isEmpty;
}
''');
- assertHasAssistAt('isEmpty', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY, '''
+ assertHasAssistAt(
+ 'isEmpty',
+ DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
+ '''
main(String str) {
'text'.isNotEmpty;
}
@@ -1436,7 +1668,10 @@
}
}
''');
- assertHasAssistAt('test)', DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, '''
+ assertHasAssistAt(
+ 'test)',
+ DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
+ '''
class A {
var test;
A(test) : test = test {
@@ -1453,7 +1688,10 @@
}
}
''');
- assertHasAssistAt('test)', DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, '''
+ assertHasAssistAt(
+ 'test)',
+ DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
+ '''
class A {
int test;
A(int test) : test = test {
@@ -1470,7 +1708,10 @@
A(this.bbb) : aaa = 1.0;
}
''');
- assertHasAssistAt('bbb)', DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, '''
+ assertHasAssistAt(
+ 'bbb)',
+ DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
+ '''
class A {
double aaa;
int bbb;
@@ -1553,7 +1794,10 @@
print(a.test);
}
''');
- assertHasAssistAt('test = 42', DartAssistKind.ENCAPSULATE_FIELD, '''
+ assertHasAssistAt(
+ 'test = 42',
+ DartAssistKind.ENCAPSULATE_FIELD,
+ '''
class A {
int _test = 42;
@@ -1579,7 +1823,10 @@
print(a.test);
}
''');
- assertHasAssistAt('test = 42', DartAssistKind.ENCAPSULATE_FIELD, '''
+ assertHasAssistAt(
+ 'test = 42',
+ DartAssistKind.ENCAPSULATE_FIELD,
+ '''
class A {
var _test = 42;
@@ -1608,7 +1855,10 @@
return a $initialOperator b;
}
''');
- assertHasAssistAt(initialOperator, DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ initialOperator,
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
bool main(int a, int b) {
return b $resultOperator a;
}
@@ -1622,7 +1872,10 @@
1 * 2 * 3 + 4;
}
''');
- assertHasAssistAt('* 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '* 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 * 3 * 1 + 4;
}
@@ -1635,7 +1888,10 @@
1 + 2 - 3 + 4;
}
''');
- assertHasAssistAt('+ 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '+ 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 + 1 - 3 + 4;
}
@@ -1648,7 +1904,10 @@
1 + 2 + 3;
}
''');
- assertHasAssistAt('+ 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '+ 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 + 3 + 1;
}
@@ -1661,7 +1920,10 @@
1 + 2 + 3;
}
''');
- assertHasAssistAt('+ 3', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '+ 3',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
3 + 1 + 2;
}
@@ -1674,7 +1936,10 @@
1 + 2;
}
''');
- assertHasAssistAt(' 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ ' 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 + 1;
}
@@ -1687,7 +1952,10 @@
1 + 2;
}
''');
- assertHasAssistAt('+ 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '+ 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 + 1;
}
@@ -1701,7 +1969,10 @@
}
''');
length = '1 + 2'.length;
- assertHasAssistAt('1 + 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '1 + 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 + 1;
}
@@ -1715,7 +1986,10 @@
}
''');
length = 2;
- assertHasAssistAt('+ 2', DartAssistKind.EXCHANGE_OPERANDS, '''
+ assertHasAssistAt(
+ '+ 2',
+ DartAssistKind.EXCHANGE_OPERANDS,
+ '''
main() {
2 + 1;
}
@@ -1784,7 +2058,10 @@
return x.foo();
}
''');
- assertHasAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW, '''
+ assertHasAssistAt(
+ 'import ',
+ DartAssistKind.IMPORT_ADD_SHOW,
+ '''
import 'dart:math' show PI;
main(x) {
PI;
@@ -1802,7 +2079,10 @@
max(1, 2);
}
''');
- assertHasAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW, '''
+ assertHasAssistAt(
+ 'import ',
+ DartAssistKind.IMPORT_ADD_SHOW,
+ '''
import 'dart:math' show E, PI, max;
main() {
PI;
@@ -1821,7 +2101,10 @@
max(1, 2);
}
''');
- assertHasAssistAt('art:math', DartAssistKind.IMPORT_ADD_SHOW, '''
+ assertHasAssistAt(
+ 'art:math',
+ DartAssistKind.IMPORT_ADD_SHOW,
+ '''
import 'dart:math' show E, PI, max;
main() {
PI;
@@ -1871,10 +2154,11 @@
''';
assertHasAssistAt(
'is MyType', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
- _assertLinkedGroup(change.linkedEditGroups[0], [
- 'myTypeName = '
- ], expectedSuggestions(
- LinkedEditSuggestionKind.VARIABLE, ['myTypeName', 'typeName', 'name']));
+ _assertLinkedGroup(
+ change.linkedEditGroups[0],
+ ['myTypeName = '],
+ expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
+ ['myTypeName', 'typeName', 'name']));
// another good location
assertHasAssistAt(
'if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
@@ -1900,10 +2184,11 @@
''';
assertHasAssistAt(
'is! MyType', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
- _assertLinkedGroup(change.linkedEditGroups[0], [
- 'myTypeName = '
- ], expectedSuggestions(
- LinkedEditSuggestionKind.VARIABLE, ['myTypeName', 'typeName', 'name']));
+ _assertLinkedGroup(
+ change.linkedEditGroups[0],
+ ['myTypeName = '],
+ expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
+ ['myTypeName', 'typeName', 'name']));
// another good location
assertHasAssistAt(
'if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
@@ -1948,7 +2233,10 @@
}
}
''');
- assertHasAssistAt('if (', DartAssistKind.INVERT_IF_STATEMENT, '''
+ assertHasAssistAt(
+ 'if (',
+ DartAssistKind.INVERT_IF_STATEMENT,
+ '''
main() {
if (false) {
1;
@@ -1968,7 +2256,10 @@
1;
}
''');
- assertHasAssistAt('if (', DartAssistKind.INVERT_IF_STATEMENT, '''
+ assertHasAssistAt(
+ 'if (',
+ DartAssistKind.INVERT_IF_STATEMENT,
+ '''
main() {
if (false)
1;
@@ -1988,7 +2279,10 @@
}
}
''');
- assertHasAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (1 == 1 && (2 == 2 || 3 == 3)) {
print(0);
@@ -2008,7 +2302,10 @@
}
bool isCheck() => false;
''');
- assertHasAssistAt('if (isCheck', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (isCheck',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (isCheck() && 2 == 2) {
print(0);
@@ -2028,7 +2325,10 @@
}
}
''');
- assertHasAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if ((1 == 1 || 2 == 2) && 3 == 3) {
print(0);
@@ -2047,7 +2347,10 @@
}
}
''');
- assertHasAssistAt('1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ '1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2066,7 +2369,10 @@
}
}
''');
- assertHasAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2084,7 +2390,10 @@
}
}
''');
- assertHasAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2105,7 +2414,10 @@
}
}
''');
- assertHasAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(1);
@@ -2125,7 +2437,10 @@
}
}
''');
- assertHasAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER, '''
+ assertHasAssistAt(
+ 'if (1 ==',
+ DartAssistKind.JOIN_IF_WITH_INNER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2194,7 +2509,10 @@
}
}
''');
- assertHasAssistAt('if (2 ==', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (2 ==',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && (2 == 2 || 3 == 3)) {
print(0);
@@ -2214,7 +2532,10 @@
}
bool isCheck() => false;
''');
- assertHasAssistAt('if (isCheck', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (isCheck',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && isCheck()) {
print(0);
@@ -2234,7 +2555,10 @@
}
}
''');
- assertHasAssistAt('if (3 == 3', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (3 == 3',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if ((1 == 1 || 2 == 2) && 3 == 3) {
print(0);
@@ -2253,7 +2577,10 @@
}
}
''');
- assertHasAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (2 == 2',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2272,7 +2599,10 @@
}
}
''');
- assertHasAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (2 == 2',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2290,7 +2620,10 @@
}
}
''');
- assertHasAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (2 == 2',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2311,7 +2644,10 @@
}
}
''');
- assertHasAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (2 == 2',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(1);
@@ -2331,7 +2667,10 @@
}
}
''');
- assertHasAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER, '''
+ assertHasAssistAt(
+ 'if (2 == 2',
+ DartAssistKind.JOIN_IF_WITH_OUTER,
+ '''
main() {
if (1 == 1 && 2 == 2) {
print(0);
@@ -2397,7 +2736,10 @@
v = 1;
}
''');
- assertHasAssistAt('v =', DartAssistKind.JOIN_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.JOIN_VARIABLE_DECLARATION,
+ '''
main() {
var v = 1;
}
@@ -2494,7 +2836,10 @@
v = 1;
}
''');
- assertHasAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'v;',
+ DartAssistKind.JOIN_VARIABLE_DECLARATION,
+ '''
main() {
var v = 1;
}
@@ -2508,7 +2853,10 @@
v = 1;
}
''');
- assertHasAssistAt('int v', DartAssistKind.JOIN_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'int v',
+ DartAssistKind.JOIN_VARIABLE_DECLARATION,
+ '''
main() {
int v = 1;
}
@@ -2522,7 +2870,10 @@
v = 1;
}
''');
- assertHasAssistAt('var v', DartAssistKind.JOIN_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'var v',
+ DartAssistKind.JOIN_VARIABLE_DECLARATION,
+ '''
main() {
var v = 1;
}
@@ -2595,7 +2946,10 @@
int v = 1;
}
''');
- assertHasAssistAt('v = ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v = ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
class A {
var v = 1;
}
@@ -2608,7 +2962,10 @@
final int v = 1;
}
''');
- assertHasAssistAt('v = ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'v = ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
class A {
final v = 1;
}
@@ -2621,7 +2978,10 @@
int a = 1, b = 2;
}
''');
- assertHasAssistAt('int ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'int ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
main() {
var a = 1, b = 2;
}
@@ -2634,7 +2994,10 @@
const int v = 1;
}
''');
- assertHasAssistAt('int ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'int ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
main() {
const v = 1;
}
@@ -2647,7 +3010,10 @@
final int v = 1;
}
''');
- assertHasAssistAt('int ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'int ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
main() {
final v = 1;
}
@@ -2658,7 +3024,10 @@
resolveTestUnit('''
int V = 1;
''');
- assertHasAssistAt('int ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'int ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
var V = 1;
''');
}
@@ -2667,7 +3036,10 @@
resolveTestUnit('''
final int V = 1;
''');
- assertHasAssistAt('int ', DartAssistKind.REMOVE_TYPE_ANNOTATION, '''
+ assertHasAssistAt(
+ 'int ',
+ DartAssistKind.REMOVE_TYPE_ANNOTATION,
+ '''
final V = 1;
''');
}
@@ -2680,7 +3052,9 @@
}
''');
// on conditional
- assertHasAssistAt('11 :', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
+ assertHasAssistAt(
+ '11 :',
+ DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
main() {
var v;
@@ -2692,7 +3066,9 @@
}
''');
// on variable
- assertHasAssistAt('v =', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
main() {
var v;
@@ -2711,8 +3087,10 @@
return true ? 111 : 222;
}
''');
- assertHasAssistAt('return ',
- DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE, '''
+ assertHasAssistAt(
+ 'return ',
+ DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
+ '''
main() {
if (true) {
return 111;
@@ -2729,7 +3107,9 @@
int a = 1, vvv = true ? 111 : 222, b = 2;
}
''');
- assertHasAssistAt('11 :', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
+ assertHasAssistAt(
+ '11 :',
+ DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
main() {
int a = 1, vvv, b = 2;
@@ -2769,8 +3149,10 @@
}
}
''');
- assertHasAssistAt('if (true)',
- DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL, '''
+ assertHasAssistAt(
+ 'if (true)',
+ DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL,
+ '''
main() {
int vvv;
vvv = true ? 111 : 222;
@@ -2788,8 +3170,10 @@
}
}
''');
- assertHasAssistAt('if (true)',
- DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL, '''
+ assertHasAssistAt(
+ 'if (true)',
+ DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL,
+ '''
main() {
return true ? 111 : 222;
}
@@ -2843,7 +3227,10 @@
}
}
''');
- assertHasAssistAt('&& 2 == 2', DartAssistKind.SPLIT_AND_CONDITION, '''
+ assertHasAssistAt(
+ '&& 2 == 2',
+ DartAssistKind.SPLIT_AND_CONDITION,
+ '''
main() {
if (1 == 1) {
if (2 == 2 && 3 == 3) {
@@ -2865,7 +3252,10 @@
}
}
''');
- assertHasAssistAt('&& false', DartAssistKind.SPLIT_AND_CONDITION, '''
+ assertHasAssistAt(
+ '&& false',
+ DartAssistKind.SPLIT_AND_CONDITION,
+ '''
main() {
if (true) {
if (false) {
@@ -2886,7 +3276,10 @@
print(0);
}
''');
- assertHasAssistAt('&& false', DartAssistKind.SPLIT_AND_CONDITION, '''
+ assertHasAssistAt(
+ '&& false',
+ DartAssistKind.SPLIT_AND_CONDITION,
+ '''
main() {
if (true)
if (false)
@@ -2967,7 +3360,10 @@
var v = 1;
}
''');
- assertHasAssistAt('v =', DartAssistKind.SPLIT_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'v =',
+ DartAssistKind.SPLIT_VARIABLE_DECLARATION,
+ '''
main() {
var v;
v = 1;
@@ -2981,7 +3377,10 @@
int v = 1;
}
''');
- assertHasAssistAt('int ', DartAssistKind.SPLIT_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'int ',
+ DartAssistKind.SPLIT_VARIABLE_DECLARATION,
+ '''
main() {
int v;
v = 1;
@@ -2995,7 +3394,10 @@
var v = 1;
}
''');
- assertHasAssistAt('var ', DartAssistKind.SPLIT_VARIABLE_DECLARATION, '''
+ assertHasAssistAt(
+ 'var ',
+ DartAssistKind.SPLIT_VARIABLE_DECLARATION,
+ '''
main() {
var v;
v = 1;
@@ -3022,7 +3424,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_BLOCK, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_BLOCK,
+ '''
main() {
// start
{
@@ -3044,7 +3448,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_DO_WHILE, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_DO_WHILE,
+ '''
main() {
// start
do {
@@ -3066,7 +3472,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_FOR, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_FOR,
+ '''
main() {
// start
for (var v = init; condition; increment) {
@@ -3088,7 +3496,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_FOR_IN, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_FOR_IN,
+ '''
main() {
// start
for (var item in iterable) {
@@ -3110,7 +3520,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_IF, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_IF,
+ '''
main() {
// start
if (condition) {
@@ -3132,7 +3544,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_TRY_CATCH, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_TRY_CATCH,
+ '''
main() {
// start
try {
@@ -3156,7 +3570,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_TRY_FINALLY, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_TRY_FINALLY,
+ '''
main() {
// start
try {
@@ -3180,7 +3596,9 @@
}
''');
_setStartEndSelection();
- assertHasAssist(DartAssistKind.SURROUND_WITH_WHILE, '''
+ assertHasAssist(
+ DartAssistKind.SURROUND_WITH_WHILE,
+ '''
main() {
// start
while (condition) {
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 4bbaeb1..f0692c6 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -47,7 +47,9 @@
$lineWithTest
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
bool b = true;
$lineWithTest
@@ -114,7 +116,9 @@
Test(this.a);
}
''');
- assertHasFix(DartFixKind.ADD_FIELD_FORMAL_PARAMETERS, '''
+ assertHasFix(
+ DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
+ '''
class Test {
final int a;
final int b;
@@ -133,7 +137,9 @@
Test();
}
''');
- assertHasFix(DartFixKind.ADD_FIELD_FORMAL_PARAMETERS, '''
+ assertHasFix(
+ DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
+ '''
class Test {
final int a;
final int b;
@@ -152,7 +158,9 @@
Test([this.c]);
}
''');
- assertHasFix(DartFixKind.ADD_FIELD_FORMAL_PARAMETERS, '''
+ assertHasFix(
+ DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
+ '''
class Test {
final int a;
final int b;
@@ -169,7 +177,9 @@
test(1);
}
''');
- assertHasFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL, '''
+ assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL,
+ '''
test([int i]) {}
main() {
test(1);
@@ -184,7 +194,9 @@
test(1, 2.0);
}
''');
- assertHasFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, '''
+ assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
+ '''
test(int a, double d) {}
main() {
test(1, 2.0);
@@ -199,7 +211,9 @@
test(1);
}
''');
- assertHasFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, '''
+ assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
+ '''
test(int i) {}
main() {
test(1);
@@ -216,7 +230,9 @@
}
}
''');
- assertHasFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL, '''
+ assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL,
+ '''
class A {
test(int a, [double d]) {}
main() {
@@ -235,7 +251,9 @@
}
}
''');
- assertHasFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, '''
+ assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
+ '''
class A {
test(int a, double d) {}
main() {
@@ -254,7 +272,9 @@
}
}
''');
- assertHasFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, '''
+ assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
+ '''
class A {
test(int i) {}
main() {
@@ -285,7 +305,9 @@
expect(fileEdits, hasLength(1));
SourceFileEdit fileEdit = change.edits[0];
expect(fileEdit.file, '/part.dart');
- expect(SourceEdit.applySequence(partCode, fileEdit.edits), r'''
+ expect(
+ SourceEdit.applySequence(partCode, fileEdit.edits),
+ r'''
// Comment first.
// Comment second.
@@ -332,7 +354,9 @@
expect(fileEdits, hasLength(1));
resultCode = SourceEdit.applySequence(testCode, fileEdits[0].edits);
// verify
- expect(resultCode, '''
+ expect(
+ resultCode,
+ '''
foo() {}
main() async {
await foo();
@@ -349,7 +373,9 @@
foo() {}
main() => await foo();
''');
- assertHasFix(DartFixKind.ADD_ASYNC, '''
+ assertHasFix(
+ DartFixKind.ADD_ASYNC,
+ '''
foo() {}
main() async => await foo();
''');
@@ -361,7 +387,9 @@
boolean v;
}
''');
- assertHasFix(DartFixKind.REPLACE_BOOLEAN_WITH_BOOL, '''
+ assertHasFix(
+ DartFixKind.REPLACE_BOOLEAN_WITH_BOOL,
+ '''
main() {
bool v;
}
@@ -377,7 +405,9 @@
a.foo();
}
''');
- assertHasFix(DartFixKind.CHANGE_TO_STATIC_ACCESS, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO_STATIC_ACCESS,
+ '''
class A {
static foo() {}
}
@@ -388,13 +418,17 @@
}
void test_changeToStaticAccess_method_importType() {
- addSource('/libA.dart', r'''
+ addSource(
+ '/libA.dart',
+ r'''
library libA;
class A {
static foo() {}
}
''');
- addSource('/libB.dart', r'''
+ addSource(
+ '/libB.dart',
+ r'''
library libB;
import 'libA.dart';
class B extends A {}
@@ -405,7 +439,9 @@
b.foo();
}
''');
- assertHasFix(DartFixKind.CHANGE_TO_STATIC_ACCESS, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO_STATIC_ACCESS,
+ '''
import 'libB.dart';
import 'libA.dart';
main(B b) {
@@ -421,7 +457,9 @@
f.wait([]);
}
''');
- assertHasFix(DartFixKind.CHANGE_TO_STATIC_ACCESS, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO_STATIC_ACCESS,
+ '''
import 'dart:async' as pref;
main(pref.Future f) {
pref.Future.wait([]);
@@ -438,7 +476,9 @@
a.foo;
}
''');
- assertHasFix(DartFixKind.CHANGE_TO_STATIC_ACCESS, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO_STATIC_ACCESS,
+ '''
class A {
static get foo => 42;
}
@@ -449,13 +489,17 @@
}
void test_changeToStaticAccess_property_importType() {
- addSource('/libA.dart', r'''
+ addSource(
+ '/libA.dart',
+ r'''
library libA;
class A {
static get foo => null;
}
''');
- addSource('/libB.dart', r'''
+ addSource(
+ '/libB.dart',
+ r'''
library libB;
import 'libA.dart';
class B extends A {}
@@ -466,7 +510,9 @@
b.foo;
}
''');
- assertHasFix(DartFixKind.CHANGE_TO_STATIC_ACCESS, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO_STATIC_ACCESS,
+ '''
import 'libB.dart';
import 'libA.dart';
main(B b) {
@@ -481,7 +527,9 @@
Test v = null;
}
''');
- assertHasFix(DartFixKind.CREATE_CLASS, '''
+ assertHasFix(
+ DartFixKind.CREATE_CLASS,
+ '''
main() {
Test v = null;
}
@@ -515,7 +563,9 @@
expect(fileEdits, hasLength(1));
SourceFileEdit fileEdit = change.edits[0];
expect(fileEdit.file, '/lib.dart');
- expect(SourceEdit.applySequence(libCode, fileEdit.edits), r'''
+ expect(
+ SourceEdit.applySequence(libCode, fileEdit.edits),
+ r'''
library my.lib;
class A {}
@@ -534,7 +584,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_CLASS, '''
+ assertHasFix(
+ DartFixKind.CREATE_CLASS,
+ '''
f() {
g() {
Test v = null;
@@ -547,6 +599,51 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
}
+ void test_createClass_itemOfList() {
+ resolveTestUnit('''
+main() {
+ var a = [Test];
+}
+''');
+ assertHasFix(
+ DartFixKind.CREATE_CLASS,
+ '''
+main() {
+ var a = [Test];
+}
+
+class Test {
+}
+''');
+ _assertLinkedGroup(change.linkedEditGroups[0], ['Test];', 'Test {']);
+ }
+
+ void test_createClass_itemOfList_inAnnotation() {
+ errorFilter = (AnalysisError error) {
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ };
+ resolveTestUnit('''
+class MyAnnotation {
+ const MyAnnotation(a, b);
+}
+@MyAnnotation(int, const [Test])
+main() {}
+''');
+ assertHasFix(
+ DartFixKind.CREATE_CLASS,
+ '''
+class MyAnnotation {
+ const MyAnnotation(a, b);
+}
+@MyAnnotation(int, const [Test])
+main() {}
+
+class Test {
+}
+''');
+ _assertLinkedGroup(change.linkedEditGroups[0], ['Test])', 'Test {']);
+ }
+
void test_createConstructor_forFinalFields() {
errorFilter = (AnalysisError error) {
return error.message.contains("'a'");
@@ -558,7 +655,9 @@
final int c;
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS,
+ '''
class Test {
final int a;
final int b = 2;
@@ -580,7 +679,9 @@
new A(1, 2.0);
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR,
+ '''
class A {
int field;
@@ -604,7 +705,9 @@
new A.named(1, 2.0);
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR,
+ '''
class A {
A.named(int i, double d) {
}
@@ -643,7 +746,9 @@
B() {}
}
''');
- assertHasFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+ assertHasFix(
+ DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
+ '''
class A {
A(bool p1, int p2, double p3, String p4, {p5});
}
@@ -663,7 +768,9 @@
B() : field = 42 {}
}
''');
- assertHasFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+ assertHasFix(
+ DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
+ '''
class A {
A(int p);
}
@@ -683,7 +790,9 @@
B() {}
}
''');
- assertHasFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+ assertHasFix(
+ DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
+ '''
class A {
A.named(int p);
}
@@ -714,7 +823,9 @@
B();
}
''');
- assertHasFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+ assertHasFix(
+ DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
+ '''
class A<T> {
A(T p);
}
@@ -735,7 +846,9 @@
void existingMethod() {}
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR_SUPER,
+ '''
class A {
A(p1, int p2, List<String> p3, [int p4]);
}
@@ -761,7 +874,9 @@
void existingMethod() {}
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR_SUPER,
+ '''
class A {
int _field;
A(this._field);
@@ -777,11 +892,15 @@
}
void test_createConstructorSuperImplicit_importType() {
- addSource('/libA.dart', r'''
+ addSource(
+ '/libA.dart',
+ r'''
library libA;
class A {}
''');
- addSource('/libB.dart', r'''
+ addSource(
+ '/libB.dart',
+ r'''
library libB;
import 'libA.dart';
class B {
@@ -793,7 +912,9 @@
class C extends B {
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR_SUPER,
+ '''
import 'libB.dart';
import 'libA.dart';
class C extends B {
@@ -813,7 +934,9 @@
void existingMethod() {}
}
''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR_SUPER,
+ '''
class A {
A.named(p1, int p2);
}
@@ -846,7 +969,9 @@
}
class D extends C<int> {
}''');
- assertHasFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER, '''
+ assertHasFix(
+ DartFixKind.CREATE_CONSTRUCTOR_SUPER,
+ '''
class C<T> {
final T x;
C(this.x);
@@ -891,7 +1016,9 @@
int v = c.b.a.test;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
}
@@ -915,7 +1042,9 @@
int v = a.test;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
}
@@ -936,7 +1065,9 @@
class B {
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
B b;
void f(Object p) {
@@ -958,7 +1089,9 @@
}
f(String s) {}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
String test;
@@ -978,7 +1111,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
@@ -997,7 +1132,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
var test;
@@ -1017,7 +1154,9 @@
int v = x.test;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
}
@@ -1037,7 +1176,9 @@
x.test = 0;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
}
@@ -1049,11 +1190,15 @@
}
void test_createField_importType() {
- addSource('/libA.dart', r'''
+ addSource(
+ '/libA.dart',
+ r'''
library libA;
class A {}
''');
- addSource('/libB.dart', r'''
+ addSource(
+ '/libB.dart',
+ r'''
library libB;
import 'libA.dart';
A getA() => null;
@@ -1066,7 +1211,9 @@
c.test = getA();
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
import 'libB.dart';
import 'libA.dart';
class C {
@@ -1089,7 +1236,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
List test;
}
@@ -1112,7 +1261,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A<T> {
List<T> items;
@@ -1137,7 +1288,9 @@
a.test = 5;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int aaa;
int zzz;
@@ -1161,7 +1314,9 @@
a.test = 5;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
@@ -1181,7 +1336,9 @@
A.test = 5;
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
static int test;
}
@@ -1199,7 +1356,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
int test;
@@ -1218,7 +1377,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FIELD, '''
+ assertHasFix(
+ DartFixKind.CREATE_FIELD,
+ '''
class A {
static int test;
@@ -1244,7 +1405,48 @@
expect(fileEdit.file, '/my/project/bin/my_file.dart');
expect(fileEdit.fileStamp, -1);
expect(fileEdit.edits, hasLength(1));
- expect(fileEdit.edits[0].replacement, contains('library my.file;'));
+ expect(fileEdit.edits[0].replacement, contains('library my_file;'));
+ }
+
+ void test_createFile_forImport_inPackage_lib() {
+ provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
+ testFile = '/projects/my_package/lib/test.dart';
+ provider.newFolder('/projects/my_package/lib');
+ resolveTestUnit('''
+import 'a/bb/c_cc/my_lib.dart';
+''');
+ AnalysisError error = _findErrorToFix();
+ fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ change = fix.change;
+ // validate change
+ List<SourceFileEdit> fileEdits = change.edits;
+ expect(fileEdits, hasLength(1));
+ SourceFileEdit fileEdit = change.edits[0];
+ expect(fileEdit.file, '/projects/my_package/lib/a/bb/c_cc/my_lib.dart');
+ expect(fileEdit.fileStamp, -1);
+ expect(fileEdit.edits, hasLength(1));
+ expect(fileEdit.edits[0].replacement,
+ contains('library my_package.a.bb.c_cc.my_lib;'));
+ }
+
+ void test_createFile_forImport_inPackage_test() {
+ provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
+ testFile = '/projects/my_package/test/misc/test_all.dart';
+ resolveTestUnit('''
+import 'a/bb/my_lib.dart';
+''');
+ AnalysisError error = _findErrorToFix();
+ fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ change = fix.change;
+ // validate change
+ List<SourceFileEdit> fileEdits = change.edits;
+ expect(fileEdits, hasLength(1));
+ SourceFileEdit fileEdit = change.edits[0];
+ expect(fileEdit.file, '/projects/my_package/test/misc/a/bb/my_lib.dart');
+ expect(fileEdit.fileStamp, -1);
+ expect(fileEdit.edits, hasLength(1));
+ expect(fileEdit.edits[0].replacement,
+ contains('library my_package.test.misc.a.bb.my_lib;'));
}
void test_createFile_forPart() {
@@ -1267,17 +1469,22 @@
}
void test_createFile_forPart_inPackageLib() {
- provider.newFile('/my/pubspec.yaml', r'''
+ provider.newFile(
+ '/my/pubspec.yaml',
+ r'''
name: my_test
''');
testFile = '/my/lib/test.dart';
- addTestSource('''
+ addTestSource(
+ '''
library my.lib;
part 'my_part.dart';
-''', Uri.parse('package:my/test.dart'));
+''',
+ Uri.parse('package:my/test.dart'));
// configure SourceFactory
- UriResolver pkgResolver = new PackageMapUriResolver(
- provider, {'my': [provider.getResource('/my/lib')],});
+ UriResolver pkgResolver = new PackageMapUriResolver(provider, {
+ 'my': [provider.getResource('/my/lib')],
+ });
context.sourceFactory = new SourceFactory(
[AbstractContextTest.SDK_RESOLVER, pkgResolver, resourceResolver]);
// prepare fix
@@ -1313,7 +1520,9 @@
int v = x.test;
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
int get test => null;
}
@@ -1338,7 +1547,9 @@
int v = c.b.a.test;
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
int get test => null;
}
@@ -1362,7 +1573,9 @@
int v = a.test;
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
int get test => null;
}
@@ -1383,7 +1596,9 @@
class B {
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
B b;
void f(Object p) {
@@ -1416,7 +1631,9 @@
}
f(String s) {}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
String get test => null;
@@ -1447,7 +1664,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
int get test => null;
@@ -1466,7 +1685,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
get test => null;
@@ -1485,7 +1706,9 @@
foo(bar);
}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
typedef MY_FUNCTION(int p);
foo(MY_FUNCTION f) {}
main() {
@@ -1511,7 +1734,9 @@
int a = test;
}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
main() {
int test;
int a = test;
@@ -1527,7 +1752,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
main() {
bool test;
if (!test) {
@@ -1544,7 +1771,9 @@
}
f(String p) {}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
main() {
String test;
f(test);
@@ -1561,7 +1790,9 @@
test.add('hello');
}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
main() {
var test;
test.add('hello');
@@ -1576,7 +1807,9 @@
test = 42;
}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
main() {
var test = 42;
}
@@ -1589,7 +1822,9 @@
test += 42;
}
''');
- assertHasFix(DartFixKind.CREATE_LOCAL_VARIABLE, '''
+ assertHasFix(
+ DartFixKind.CREATE_LOCAL_VARIABLE,
+ '''
main() {
int test;
test += 42;
@@ -1608,7 +1843,9 @@
class MyEmulator extends Emulator {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
typedef int Binary(int left, int right);
abstract class Emulator {
@@ -1633,7 +1870,9 @@
class B extends A {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
abstract class A {
forEach(int f(double p1, String p2));
}
@@ -1659,7 +1898,9 @@
class Test extends IterableMixin<int> {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
class Iterator<T> {
}
@@ -1684,7 +1925,9 @@
class Test<V> extends ItemProvider<V> {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
abstract class ItemProvider<T> {
List<T> getItems();
}
@@ -1708,7 +1951,9 @@
class B extends A {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
abstract class A {
get g1;
int get g2;
@@ -1736,7 +1981,9 @@
class B extends A {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
import 'dart:async' as aaa;
abstract class A {
Map<aaa.Future, List<aaa.Future>> g(aaa.Future p);
@@ -1762,7 +2009,9 @@
class B implements A {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
class A {
int ma;
void mb() {}
@@ -1865,7 +2114,9 @@
class B extends A {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
abstract class A {
int operator [](int index);
void operator []=(int index, String value);
@@ -1896,7 +2147,9 @@
class B extends A {
}
''');
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, '''
+ assertHasFix(
+ DartFixKind.CREATE_MISSING_OVERRIDES,
+ '''
abstract class A {
set s1(x);
set s2(int x);
@@ -1933,7 +2186,9 @@
existing() {}
}
''');
- assertHasFix(DartFixKind.CREATE_NO_SUCH_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_NO_SUCH_METHOD,
+ '''
abstract class A {
m1();
int m2();
@@ -1960,7 +2215,9 @@
int v = a.test;
}
''');
- assertHasFix(DartFixKind.CREATE_GETTER, '''
+ assertHasFix(
+ DartFixKind.CREATE_GETTER,
+ '''
class A {
int existingField;
@@ -1990,7 +2247,9 @@
a..ma().useFunction(test);
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
class A {
B ma() => null;
}
@@ -2015,7 +2274,9 @@
}
useFunction({Function g}) {}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
useFunction(g: test);
}
@@ -2033,7 +2294,9 @@
}
useFunction(int g(a, b)) {}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
useFunction(test);
}
@@ -2051,7 +2314,9 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
useFunction(test);
}
@@ -2069,7 +2334,9 @@
}
useFunction({int g(double a, String b)}) {}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
useFunction(g: test);
}
@@ -2081,11 +2348,15 @@
}
void test_creationFunction_forFunctionType_importType() {
- addSource('/libA.dart', r'''
+ addSource(
+ '/libA.dart',
+ r'''
library libA;
class A {}
''');
- addSource('/libB.dart', r'''
+ addSource(
+ '/libB.dart',
+ r'''
library libB;
import 'libA.dart';
useFunction(int g(A a)) {}
@@ -2096,7 +2367,9 @@
useFunction(test);
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
import 'libB.dart';
import 'libA.dart';
main() {
@@ -2117,7 +2390,9 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
static foo() {
useFunction(test);
@@ -2138,7 +2413,9 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
var f;
A() : f = useFunction(test);
@@ -2159,7 +2436,9 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
main(A a) {
useFunction(a.test);
}
@@ -2181,7 +2460,9 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
main(A a) {
useFunction(a.test);
}
@@ -2225,7 +2506,9 @@
print(0)
}
''');
- assertHasFix(DartFixKind.INSERT_SEMICOLON, '''
+ assertHasFix(
+ DartFixKind.INSERT_SEMICOLON,
+ '''
main() {
print(0);
}
@@ -2241,7 +2524,9 @@
int main() async {
}
''');
- assertHasFix(DartFixKind.REPLACE_RETURN_TYPE_FUTURE, '''
+ assertHasFix(
+ DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
+ '''
library main;
import 'dart:async';
Future<int> main() async {
@@ -2258,7 +2543,9 @@
int main() async {
}
''');
- assertHasFix(DartFixKind.REPLACE_RETURN_TYPE_FUTURE, '''
+ assertHasFix(
+ DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
+ '''
import 'dart:async' as al;
al.Future<int> main() async {
}
@@ -2274,7 +2561,9 @@
List<int> main() async {
}
''');
- assertHasFix(DartFixKind.REPLACE_RETURN_TYPE_FUTURE, '''
+ assertHasFix(
+ DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
+ '''
import 'dart:async';
Future<List<int>> main() async {
}
@@ -2290,7 +2579,9 @@
void main() async {
}
''');
- assertHasFix(DartFixKind.REPLACE_RETURN_TYPE_FUTURE, '''
+ assertHasFix(
+ DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
+ '''
import 'dart:async';
Future main() async {
}
@@ -2309,7 +2600,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'package:my_pkg/my_lib.dart';
main() {
@@ -2326,7 +2619,9 @@
Future f = null;
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PREFIX, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PREFIX,
+ '''
import 'dart:async' as pref;
main() {
pref.Stream s = null;
@@ -2343,7 +2638,9 @@
print(PI);
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PREFIX, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PREFIX,
+ '''
import 'dart:math' as pref;
main() {
print(pref.E);
@@ -2353,7 +2650,9 @@
}
void test_importLibraryProject_withClass_annotation() {
- addSource('/lib.dart', '''
+ addSource(
+ '/lib.dart',
+ '''
library lib;
class Test {
const Test(int p);
@@ -2365,7 +2664,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'lib.dart';
@Test(0)
@@ -2376,7 +2677,9 @@
void test_importLibraryProject_withClass_inParentFolder() {
testFile = '/project/bin/test.dart';
- addSource('/project/lib.dart', '''
+ addSource(
+ '/project/lib.dart',
+ '''
library lib;
class Test {}
''');
@@ -2386,7 +2689,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import '../lib.dart';
main() {
@@ -2397,7 +2702,9 @@
void test_importLibraryProject_withClass_inRelativeFolder() {
testFile = '/project/bin/test.dart';
- addSource('/project/lib/sub/folder/lib.dart', '''
+ addSource(
+ '/project/lib/sub/folder/lib.dart',
+ '''
library lib;
class Test {}
''');
@@ -2407,7 +2714,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import '../lib/sub/folder/lib.dart';
main() {
@@ -2418,7 +2727,9 @@
void test_importLibraryProject_withClass_inSameFolder() {
testFile = '/project/bin/test.dart';
- addSource('/project/bin/lib.dart', '''
+ addSource(
+ '/project/bin/lib.dart',
+ '''
library lib;
class Test {}
''');
@@ -2428,7 +2739,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'lib.dart';
main() {
@@ -2438,7 +2751,9 @@
}
void test_importLibraryProject_withFunction() {
- addSource('/lib.dart', '''
+ addSource(
+ '/lib.dart',
+ '''
library lib;
myFunction() {}
''');
@@ -2448,7 +2763,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'lib.dart';
main() {
@@ -2458,7 +2775,9 @@
}
void test_importLibraryProject_withFunction_unresolvedMethod() {
- addSource('/lib.dart', '''
+ addSource(
+ '/lib.dart',
+ '''
library lib;
myFunction() {}
''');
@@ -2470,7 +2789,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'lib.dart';
class A {
@@ -2483,7 +2804,9 @@
void test_importLibraryProject_withFunctionTypeAlias() {
testFile = '/project/bin/test.dart';
- addSource('/project/bin/lib.dart', '''
+ addSource(
+ '/project/bin/lib.dart',
+ '''
library lib;
typedef MyFunction();
''');
@@ -2493,7 +2816,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'lib.dart';
main() {
@@ -2503,7 +2828,9 @@
}
void test_importLibraryProject_withTopLevelVariable() {
- addSource('/lib.dart', '''
+ addSource(
+ '/lib.dart',
+ '''
library lib;
int MY_VAR = 42;
''');
@@ -2513,7 +2840,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_PROJECT,
+ '''
import 'lib.dart';
main() {
@@ -2528,7 +2857,9 @@
p as Future;
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:async';
main(p) {
@@ -2543,7 +2874,9 @@
Future.wait(null);
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:async';
main() {
@@ -2558,7 +2891,9 @@
p is Future;
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:async';
main(p) {
@@ -2567,13 +2902,57 @@
''');
}
+ void test_importLibrarySdk_withClass_itemOfList() {
+ resolveTestUnit('''
+main() {
+ var a = [Future];
+}
+''');
+ performAllAnalysisTasks();
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
+import 'dart:async';
+
+main() {
+ var a = [Future];
+}
+''');
+ }
+
+ void test_importLibrarySdk_withClass_itemOfList_inAnnotation() {
+ errorFilter = (AnalysisError error) {
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ };
+ resolveTestUnit('''
+class MyAnnotation {
+ const MyAnnotation(a, b);
+}
+@MyAnnotation(int, const [Future])
+main() {}
+''');
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
+import 'dart:async';
+
+class MyAnnotation {
+ const MyAnnotation(a, b);
+}
+@MyAnnotation(int, const [Future])
+main() {}
+''');
+ }
+
void test_importLibrarySdk_withClass_typeAnnotation() {
resolveTestUnit('''
main() {
Future f = null;
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:async';
main() {
@@ -2588,7 +2967,9 @@
Future.wait;
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:async';
main() {
@@ -2603,7 +2984,9 @@
List<Future> futures = [];
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:async';
main() {
@@ -2619,7 +3002,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:math';
main() {
@@ -2635,7 +3020,9 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SDK, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SDK,
+ '''
import 'dart:math';
@PI
@@ -2652,7 +3039,9 @@
Future f = null;
}
''');
- assertHasFix(DartFixKind.IMPORT_LIBRARY_SHOW, '''
+ assertHasFix(
+ DartFixKind.IMPORT_LIBRARY_SHOW,
+ '''
import 'dart:async' show Future, Stream;
main() {
Stream s = null;
@@ -2667,7 +3056,9 @@
p is! Null;
}
''');
- assertHasFix(DartFixKind.USE_NOT_EQ_NULL, '''
+ assertHasFix(
+ DartFixKind.USE_NOT_EQ_NULL,
+ '''
main(p) {
p != null;
}
@@ -2680,7 +3071,9 @@
p is Null;
}
''');
- assertHasFix(DartFixKind.USE_EQ_EQ_NULL, '''
+ assertHasFix(
+ DartFixKind.USE_EQ_EQ_NULL,
+ '''
main(p) {
p == null;
}
@@ -2693,7 +3086,9 @@
m();
}
''');
- assertHasFix(DartFixKind.MAKE_CLASS_ABSTRACT, '''
+ assertHasFix(
+ DartFixKind.MAKE_CLASS_ABSTRACT,
+ '''
abstract class A {
m();
}
@@ -2708,7 +3103,9 @@
class B extends A {
}
''');
- assertHasFix(DartFixKind.MAKE_CLASS_ABSTRACT, '''
+ assertHasFix(
+ DartFixKind.MAKE_CLASS_ABSTRACT,
+ '''
abstract class A {
m();
}
@@ -2736,7 +3133,9 @@
}
}
''');
- assertHasFix(DartFixKind.REMOVE_DEAD_CODE, '''
+ assertHasFix(
+ DartFixKind.REMOVE_DEAD_CODE,
+ '''
main(int p) {
if (true) {
print(1);
@@ -2753,7 +3152,9 @@
print(1);
}
''');
- assertHasFix(DartFixKind.REMOVE_DEAD_CODE, '''
+ assertHasFix(
+ DartFixKind.REMOVE_DEAD_CODE,
+ '''
int main() {
print(0);
return 42;
@@ -2770,7 +3171,9 @@
print(2);
}
''');
- assertHasFix(DartFixKind.REMOVE_DEAD_CODE, '''
+ assertHasFix(
+ DartFixKind.REMOVE_DEAD_CODE,
+ '''
int main() {
print(0);
return 42;
@@ -2784,7 +3187,9 @@
int get foo() => 0;
}
''');
- assertHasFix(DartFixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, '''
+ assertHasFix(
+ DartFixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION,
+ '''
class A {
int get foo => 0;
}
@@ -2800,7 +3205,9 @@
a.foo();
}
''');
- assertHasFix(DartFixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, '''
+ assertHasFix(
+ DartFixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION,
+ '''
class A {
int get foo => 0;
}
@@ -2818,7 +3225,9 @@
}
}
''');
- assertHasFix(DartFixKind.REMOVE_UNNECASSARY_CAST, '''
+ assertHasFix(
+ DartFixKind.REMOVE_UNNECASSARY_CAST,
+ '''
main(Object p) {
if (p is String) {
String v = p;
@@ -2837,7 +3246,9 @@
}
}
''');
- assertHasFix(DartFixKind.REMOVE_UNUSED_CATCH_CLAUSE, '''
+ assertHasFix(
+ DartFixKind.REMOVE_UNUSED_CATCH_CLAUSE,
+ '''
main() {
try {
throw 42;
@@ -2857,7 +3268,9 @@
}
}
''');
- assertHasFix(DartFixKind.REMOVE_UNUSED_CATCH_STACK, '''
+ assertHasFix(
+ DartFixKind.REMOVE_UNUSED_CATCH_STACK,
+ '''
main() {
try {
throw 42;
@@ -2873,7 +3286,9 @@
main() {
}
''');
- assertHasFix(DartFixKind.REMOVE_UNUSED_IMPORT, '''
+ assertHasFix(
+ DartFixKind.REMOVE_UNUSED_IMPORT,
+ '''
main() {
}
''');
@@ -2887,7 +3302,9 @@
Future f;
}
''');
- assertHasFix(DartFixKind.REMOVE_UNUSED_IMPORT, '''
+ assertHasFix(
+ DartFixKind.REMOVE_UNUSED_IMPORT,
+ '''
import 'dart:async';
main() {
@@ -2903,7 +3320,9 @@
main() {
}
''');
- assertHasFix(DartFixKind.REMOVE_UNUSED_IMPORT, '''
+ assertHasFix(
+ DartFixKind.REMOVE_UNUSED_IMPORT,
+ '''
main() {
}
''');
@@ -2916,7 +3335,9 @@
import 'no/matter/lib.dart';
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.REPLACE_IMPORT_URI, '''
+ assertHasFix(
+ DartFixKind.REPLACE_IMPORT_URI,
+ '''
import '../foo/bar/lib.dart';
''');
}
@@ -2927,7 +3348,9 @@
import 'no/matter/my_lib.dart';
''');
performAllAnalysisTasks();
- assertHasFix(DartFixKind.REPLACE_IMPORT_URI, '''
+ assertHasFix(
+ DartFixKind.REPLACE_IMPORT_URI,
+ '''
import 'package:my_pkg/my_lib.dart';
''');
}
@@ -2941,7 +3364,9 @@
Map<String, var> m;
}
''');
- assertHasFix(DartFixKind.REPLACE_VAR_WITH_DYNAMIC, '''
+ assertHasFix(
+ DartFixKind.REPLACE_VAR_WITH_DYNAMIC,
+ '''
class A {
Map<String, dynamic> m;
}
@@ -2955,7 +3380,9 @@
}
const a = new A();
''');
- assertHasFix(DartFixKind.USE_CONST, '''
+ assertHasFix(
+ DartFixKind.USE_CONST,
+ '''
class A {
const A();
}
@@ -2969,7 +3396,9 @@
Stirng s = 'abc';
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
main() {
String s = 'abc';
}
@@ -2983,7 +3412,9 @@
MyCalss v = null;
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class MyClass {}
main() {
MyClass v = null;
@@ -2998,7 +3429,9 @@
test(v);
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
dynamic v;
test(v);
@@ -3015,7 +3448,9 @@
dynamic v = test();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
dynamic v = test();
}
@@ -3031,7 +3466,9 @@
int v = myUndefinedFunction(1, 2.0, '3');
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
int v = myUndefinedFunction(1, 2.0, '3');
}
@@ -3049,7 +3486,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
class A {
main() {
int v = myUndefinedFunction(1, 2.0, '3');
@@ -3070,7 +3509,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
class A<T> {
Map<int, T> items;
main() {
@@ -3092,7 +3533,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
class A {
List<int> items;
main() {
@@ -3106,7 +3549,9 @@
}
void test_undefinedFunction_create_importType() {
- addSource('/lib.dart', r'''
+ addSource(
+ '/lib.dart',
+ r'''
library lib;
import 'dart:async';
Future getFuture() => null;
@@ -3117,7 +3562,9 @@
test(getFuture());
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
import 'lib.dart';
import 'dart:async';
main() {
@@ -3135,7 +3582,9 @@
test(null);
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
test(null);
}
@@ -3167,7 +3616,9 @@
v = myUndefinedFunction();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
int v;
v = myUndefinedFunction();
@@ -3185,7 +3636,9 @@
v += myUndefinedFunction();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
int v;
v += myUndefinedFunction();
@@ -3202,7 +3655,9 @@
0 + myUndefinedFunction();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
0 + myUndefinedFunction();
}
@@ -3218,7 +3673,9 @@
int v = myUndefinedFunction();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
int v = myUndefinedFunction();
}
@@ -3235,7 +3692,9 @@
foo( myUndefinedFunction() );
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
foo(int p) {}
main() {
foo( myUndefinedFunction() );
@@ -3252,7 +3711,9 @@
return myUndefinedFunction();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
int main() {
return myUndefinedFunction();
}
@@ -3268,7 +3729,9 @@
myUndefinedFunction();
}
''');
- assertHasFix(DartFixKind.CREATE_FUNCTION, '''
+ assertHasFix(
+ DartFixKind.CREATE_FUNCTION,
+ '''
main() {
myUndefinedFunction();
}
@@ -3284,7 +3747,9 @@
pritn(0);
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
main() {
print(0);
}
@@ -3298,7 +3763,9 @@
myFuntcion();
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
myFunction() {}
main() {
myFunction();
@@ -3316,7 +3783,9 @@
print(x.myFild);
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
int myField;
}
@@ -3336,7 +3805,9 @@
print(a.myFild);
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
int myField;
}
@@ -3355,7 +3826,9 @@
A.MY_NAM;
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
static int MY_NAME = 1;
}
@@ -3374,7 +3847,9 @@
}
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
int myField;
main() {
@@ -3406,7 +3881,9 @@
class B {
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A<T> {
B b;
Map<int, T> items;
@@ -3433,7 +3910,9 @@
class B {
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A<T> {
main() {
T t = new B().compute();
@@ -3460,7 +3939,9 @@
class B {
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
B b;
List<int> items;
@@ -3485,7 +3966,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A<T> {
List<T> items;
main() {
@@ -3506,7 +3989,9 @@
A.myUndefinedMethod();
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
static void myUndefinedMethod() {
}
@@ -3526,7 +4011,9 @@
A.myUndefinedMethod();
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
foo() {}
@@ -3547,7 +4034,9 @@
a.myUndefinedMethod();
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
void myUndefinedMethod() {
}
@@ -3585,7 +4074,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
main() {
myUndefinedMethod(0, 1.0, '3');
@@ -3599,24 +4090,23 @@
int index = 0;
_assertLinkedGroup(
change.linkedEditGroups[index++], ['void myUndefinedMethod(']);
- _assertLinkedGroup(change.linkedEditGroups[index++], [
- 'myUndefinedMethod(0',
- 'myUndefinedMethod(int'
- ]);
- _assertLinkedGroup(change.linkedEditGroups[index++], [
- 'int i'
- ], expectedSuggestions(
- LinkedEditSuggestionKind.TYPE, ['int', 'num', 'Object', 'Comparable']));
+ _assertLinkedGroup(change.linkedEditGroups[index++],
+ ['myUndefinedMethod(0', 'myUndefinedMethod(int']);
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++],
+ ['int i'],
+ expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+ ['int', 'num', 'Object', 'Comparable']));
_assertLinkedGroup(change.linkedEditGroups[index++], ['i,']);
- _assertLinkedGroup(change.linkedEditGroups[index++], ['double d'],
- expectedSuggestions(LinkedEditSuggestionKind.TYPE, [
- 'double',
- 'num',
- 'Object',
- 'Comparable'
- ]));
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++],
+ ['double d'],
+ expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+ ['double', 'num', 'Object', 'Comparable']));
_assertLinkedGroup(change.linkedEditGroups[index++], ['d,']);
- _assertLinkedGroup(change.linkedEditGroups[index++], ['String s'],
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++],
+ ['String s'],
expectedSuggestions(
LinkedEditSuggestionKind.TYPE, ['String', 'Object', 'Comparable']));
_assertLinkedGroup(change.linkedEditGroups[index++], ['s)']);
@@ -3630,7 +4120,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
main() {
int v = myUndefinedMethod();
@@ -3642,10 +4134,8 @@
''');
// linked positions
_assertLinkedGroup(change.linkedEditGroups[0], ['int myUndefinedMethod(']);
- _assertLinkedGroup(change.linkedEditGroups[1], [
- 'myUndefinedMethod();',
- 'myUndefinedMethod() {'
- ]);
+ _assertLinkedGroup(change.linkedEditGroups[1],
+ ['myUndefinedMethod();', 'myUndefinedMethod() {']);
}
void test_undefinedMethod_createUnqualified_staticFromField() {
@@ -3654,7 +4144,9 @@
static var f = myUndefinedMethod();
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
static var f = myUndefinedMethod();
@@ -3672,7 +4164,9 @@
}
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
static main() {
myUndefinedMethod();
@@ -3693,7 +4187,9 @@
a.myUndefinedMethod();
}
''');
- assertHasFix(DartFixKind.CREATE_METHOD, '''
+ assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
class A {
void myUndefinedMethod() {
}
@@ -3724,7 +4220,9 @@
a.myMehtod();
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
myMethod() {}
}
@@ -3746,7 +4244,9 @@
}
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
myMethod() {}
}
@@ -3767,7 +4267,9 @@
}
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
myMethod() {}
main() {
@@ -3787,7 +4289,9 @@
x.myFild = 42;
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
int myField;
}
@@ -3807,7 +4311,9 @@
a.myFild = 42;
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
int myField;
}
@@ -3826,7 +4332,9 @@
}
}
''');
- assertHasFix(DartFixKind.CHANGE_TO, '''
+ assertHasFix(
+ DartFixKind.CHANGE_TO,
+ '''
class A {
int myField;
main() {
@@ -3844,7 +4352,9 @@
print((a / b).toInt());
}
''');
- assertHasFix(DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION, '''
+ assertHasFix(
+ DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION,
+ '''
main() {
var a = 5;
var b = 2;
@@ -3879,7 +4389,7 @@
* Computes fixes for the given [error] in [testUnit].
*/
List<Fix> _computeFixes(AnalysisError error) {
- FixProcessor processor = new FixProcessor(testUnit, error);
+ FixProcessor processor = new FixProcessor(provider, testUnit, error);
return processor.compute();
}
@@ -3891,8 +4401,9 @@
provider.newFile('/packages/my_pkg/lib/my_lib.dart', myLibCode);
// configure SourceFactory
Folder myPkgFolder = provider.getResource('/packages/my_pkg/lib');
- UriResolver pkgResolver =
- new PackageMapUriResolver(provider, {'my_pkg': [myPkgFolder]});
+ UriResolver pkgResolver = new PackageMapUriResolver(provider, {
+ 'my_pkg': [myPkgFolder]
+ });
context.sourceFactory = new SourceFactory(
[AbstractContextTest.SDK_RESOLVER, resourceResolver, pkgResolver]);
// force 'my_pkg' resolution
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
new file mode 100644
index 0000000..d9423a4
--- /dev/null
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -0,0 +1,253 @@
+// 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.refactoring.organize_directives;
+
+import 'package:analysis_server/src/protocol.dart' hide AnalysisError;
+import 'package:analysis_server/src/services/correction/organize_directives.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../abstract_single_unit.dart';
+
+main() {
+ groupSep = ' | ';
+ defineReflectiveTests(OrganizeDirectivesTest);
+}
+
+@reflectiveTest
+class OrganizeDirectivesTest extends AbstractSingleUnitTest {
+ List<AnalysisError> testErrors;
+
+ void test_remove_unresolvedDirectives() {
+ addSource('/existing_part1.dart', 'part of lib;');
+ addSource('/existing_part2.dart', 'part of lib;');
+ _computeUnitAndErrors(r'''
+library lib;
+
+import 'dart:async';
+import 'dart:noSuchImportSdkLibrary';
+import 'dart:math';
+import 'package:noSuchImportPackage/andLib.dart';
+
+export 'dart:noSuchExportSdkLibrary';
+export 'dart:async';
+export 'package:noSuchExportPackage/andLib.dart';
+export 'dart:math';
+
+part 'existing_part1.dart';
+part 'no_such_part.dart';
+part 'existing_part2.dart';
+
+main() {
+}
+''');
+ // validate change
+ _assertOrganize(
+ r'''
+library lib;
+
+import 'dart:async';
+import 'dart:math';
+
+export 'dart:async';
+export 'dart:math';
+
+part 'existing_part1.dart';
+part 'existing_part2.dart';
+
+main() {
+}
+''',
+ removeUnresolved: true);
+ }
+
+ void test_remove_unusedImports() {
+ _computeUnitAndErrors(r'''
+library lib;
+
+import 'dart:async';
+import 'dart:math';
+import 'dart:convert';
+import 'dart:collection';
+
+main() {
+ print(PI);
+ new HashMap();
+}
+''');
+ // validate change
+ _assertOrganize(
+ r'''
+library lib;
+
+import 'dart:collection';
+import 'dart:math';
+
+main() {
+ print(PI);
+ new HashMap();
+}
+''',
+ removeUnused: true);
+ }
+
+ void test_remove_unusedImports2() {
+ _computeUnitAndErrors(r'''
+import 'dart:async';
+import 'dart:math';
+
+class A {}
+
+main() {
+ Future f;
+}''');
+ // validate change
+ _assertOrganize(
+ r'''
+import 'dart:async';
+
+class A {}
+
+main() {
+ Future f;
+}''',
+ removeUnresolved: true,
+ removeUnused: true);
+ }
+
+ void test_sort() {
+ _computeUnitAndErrors(r'''
+library lib;
+
+export 'dart:bbb';
+import 'dart:bbb';
+export 'package:bbb/bbb.dart';
+export 'http://bbb.com';
+import 'bbb/bbb.dart';
+export 'http://aaa.com';
+import 'http://bbb.com';
+export 'dart:aaa';
+export 'package:aaa/aaa.dart';
+import 'package:bbb/bbb.dart';
+export 'aaa/aaa.dart';
+export 'bbb/bbb.dart';
+import 'dart:aaa';
+import 'package:aaa/aaa.dart';
+import 'aaa/aaa.dart';
+import 'http://aaa.com';
+part 'bbb/bbb.dart';
+part 'aaa/aaa.dart';
+
+main() {
+}
+''');
+ // validate change
+ _assertOrganize(r'''
+library lib;
+
+import 'dart:aaa';
+import 'dart:bbb';
+
+import 'package:aaa/aaa.dart';
+import 'package:bbb/bbb.dart';
+
+import 'http://aaa.com';
+import 'http://bbb.com';
+
+import 'aaa/aaa.dart';
+import 'bbb/bbb.dart';
+
+export 'dart:aaa';
+export 'dart:bbb';
+
+export 'package:aaa/aaa.dart';
+export 'package:bbb/bbb.dart';
+
+export 'http://aaa.com';
+export 'http://bbb.com';
+
+export 'aaa/aaa.dart';
+export 'bbb/bbb.dart';
+
+part 'aaa/aaa.dart';
+part 'bbb/bbb.dart';
+
+main() {
+}
+''');
+ }
+
+ void test_sort_hasComments() {
+ _computeUnitAndErrors(r'''
+// header
+library lib;
+
+import 'c.dart';// c
+import 'a.dart';// aa
+import 'b.dart';// bbb
+
+/** doc */
+main() {
+}
+''');
+ // validate change
+ _assertOrganize(r'''
+// header
+library lib;
+
+import 'a.dart';
+import 'b.dart';
+import 'c.dart';
+// c
+// aa
+// bbb
+
+/** doc */
+main() {
+}
+''');
+ }
+
+ void test_sort_imports_packageAndPath() {
+ _computeUnitAndErrors(r'''
+library lib;
+
+import 'package:product.ui.api.bbb/manager1.dart';
+import 'package:product.ui.api/entity2.dart';
+import 'package:product.ui/entity.dart';
+import 'package:product.ui.api.aaa/manager2.dart';
+import 'package:product.ui.api/entity1.dart';
+import 'package:product2.client/entity.dart';
+''');
+ // validate change
+ _assertOrganize(r'''
+library lib;
+
+import 'package:product.ui/entity.dart';
+import 'package:product.ui.api/entity1.dart';
+import 'package:product.ui.api/entity2.dart';
+import 'package:product.ui.api.aaa/manager2.dart';
+import 'package:product.ui.api.bbb/manager1.dart';
+import 'package:product2.client/entity.dart';
+''');
+ }
+
+ void _assertOrganize(String expectedCode,
+ {bool removeUnresolved: false, bool removeUnused: false}) {
+ DirectiveOrganizer organizer = new DirectiveOrganizer(
+ testCode, testUnit, testErrors,
+ removeUnresolved: removeUnresolved, removeUnused: removeUnused);
+ List<SourceEdit> edits = organizer.organize();
+ String result = SourceEdit.applySequence(testCode, edits);
+ expect(result, expectedCode);
+ }
+
+ void _computeUnitAndErrors(String code) {
+ addTestSource(code);
+ testUnit = context.resolveCompilationUnit2(testSource, testSource);
+ testErrors = context.computeErrors(testSource);
+ }
+}
diff --git a/pkg/analysis_server/test/services/correction/test_all.dart b/pkg/analysis_server/test/services/correction/test_all.dart
index 3f3b03e..418fa67 100644
--- a/pkg/analysis_server/test/services/correction/test_all.dart
+++ b/pkg/analysis_server/test/services/correction/test_all.dart
@@ -11,6 +11,7 @@
import 'fix_test.dart' as fix_test;
import 'levenshtein_test.dart' as levenshtein_test;
import 'name_suggestion_test.dart' as name_suggestion_test;
+import 'organize_directives_test.dart' as organize_directives_test;
import 'sort_members_test.dart' as sort_members_test;
import 'source_range_test.dart' as source_range_test;
import 'status_test.dart' as status_test;
@@ -25,6 +26,7 @@
fix_test.main();
levenshtein_test.main();
name_suggestion_test.main();
+ organize_directives_test.main();
sort_members_test.main();
source_range_test.main();
status_test.main();
diff --git a/pkg/analysis_server/test/source/optimizing_pub_package_map_provider_test.dart b/pkg/analysis_server/test/source/optimizing_pub_package_map_provider_test.dart
deleted file mode 100644
index 4f68485..0000000
--- a/pkg/analysis_server/test/source/optimizing_pub_package_map_provider_test.dart
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.source.optimizing_pub_package_map_provider;
-
-import 'dart:convert';
-import 'dart:io' as io;
-
-import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:path/path.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'package:unittest/unittest.dart';
-
-main() {
- groupSep = ' | ';
- defineReflectiveTests(OptimizingPubPackageMapProviderTest);
- defineReflectiveTests(OptimizingPubPackageMapInfoTest);
-}
-
-@reflectiveTest
-class OptimizingPubPackageMapInfoTest {
- MemoryResourceProvider resourceProvider;
-
- int createFile(String path) {
- return resourceProvider.newFile(path, 'contents').modificationStamp;
- }
-
- void createFolder(String path) {
- resourceProvider.newFolder(path);
- }
-
- void modifyFile(String path) {
- resourceProvider.modifyFile(path, 'contents');
- }
-
- void setUp() {
- resourceProvider = new MemoryResourceProvider();
- }
-
- test_isChangedDependency_fileNotPresent() {
- String path = '/dep';
- int timestamp = 1;
- OptimizingPubPackageMapInfo info =
- new OptimizingPubPackageMapInfo({}, [path].toSet(), {path: timestamp});
- expect(info.isChangedDependency(path, resourceProvider), isTrue);
- }
-
- test_isChangedDependency_matchingTimestamp() {
- String path = '/dep';
- int timestamp = createFile(path);
- OptimizingPubPackageMapInfo info =
- new OptimizingPubPackageMapInfo({}, [path].toSet(), {path: timestamp});
- expect(info.isChangedDependency(path, resourceProvider), isFalse);
- }
-
- test_isChangedDependency_mismatchedTimestamp() {
- String path = '/dep';
- int timestamp = createFile(path);
- OptimizingPubPackageMapInfo info =
- new OptimizingPubPackageMapInfo({}, [path].toSet(), {path: timestamp});
- modifyFile(path);
- expect(info.isChangedDependency(path, resourceProvider), isTrue);
- }
-
- test_isChangedDependency_nonDependency() {
- OptimizingPubPackageMapInfo info =
- new OptimizingPubPackageMapInfo({}, ['/dep1'].toSet(), {});
- expect(info.isChangedDependency('/dep2', resourceProvider), isFalse);
- }
-
- test_isChangedDependency_nonFile() {
- String path = '/dep';
- int timestamp = 1;
- createFolder(path);
- OptimizingPubPackageMapInfo info =
- new OptimizingPubPackageMapInfo({}, [path].toSet(), {path: timestamp});
- expect(info.isChangedDependency(path, resourceProvider), isTrue);
- }
-
- test_isChangedDependency_noTimestampInfo() {
- String path = '/dep';
- OptimizingPubPackageMapInfo info =
- new OptimizingPubPackageMapInfo({}, [path].toSet(), {});
- expect(info.isChangedDependency(path, resourceProvider), isTrue);
- }
-}
-
-@reflectiveTest
-class OptimizingPubPackageMapProviderTest {
- MemoryResourceProvider resourceProvider;
- OptimizingPubPackageMapProvider provider;
- Folder projectFolder;
- io.ProcessResult pubListResult;
-
- void setPubListError() {
- pubListResult = new _MockProcessResult(0, 1, '', 'ERROR');
- }
-
- void setPubListResult({Map<String, String> packages: const {},
- List<String> input_files: const []}) {
- pubListResult = new _MockProcessResult(0, 0,
- JSON.encode({'packages': packages, 'input_files': input_files}), '');
- }
-
- void setUp() {
- resourceProvider = new MemoryResourceProvider();
- provider = new OptimizingPubPackageMapProvider(
- resourceProvider, null, _runPubList);
- projectFolder = resourceProvider.newFolder('/my/proj');
- }
-
- test_computePackageMap_noPreviousInfo() {
- String dep = posix.join(projectFolder.path, 'dep');
- String pkgName = 'foo';
- String pkgPath = '/pkg/foo';
- setPubListResult(packages: {pkgName: pkgPath}, input_files: [dep]);
- OptimizingPubPackageMapInfo info =
- provider.computePackageMap(projectFolder);
- expect(info.dependencies, hasLength(1));
- expect(info.dependencies, contains(dep));
- expect(info.packageMap, hasLength(1));
- expect(info.packageMap, contains(pkgName));
- expect(info.packageMap[pkgName], hasLength(1));
- expect(info.packageMap[pkgName][0].path, pkgPath);
- expect(info.modificationTimes, isEmpty);
- }
-
- test_computePackageMap_noPreviousInfo_pubListError() {
- String pubspecLock = posix.join(projectFolder.path, 'pubspec.lock');
- setPubListError();
- OptimizingPubPackageMapInfo info =
- provider.computePackageMap(projectFolder);
- expect(info.dependencies, hasLength(1));
- expect(info.dependencies, contains(pubspecLock));
- expect(info.packageMap, isNull);
- expect(info.modificationTimes, isEmpty);
- }
-
- test_computePackageMap_withPreviousInfo() {
- String dep = posix.join(projectFolder.path, 'dep');
- int timestamp = resourceProvider.newFile(dep, 'contents').modificationStamp;
- setPubListResult(input_files: [dep]);
- OptimizingPubPackageMapInfo info1 =
- provider.computePackageMap(projectFolder);
- OptimizingPubPackageMapInfo info2 =
- provider.computePackageMap(projectFolder, info1);
- expect(info2.dependencies, hasLength(1));
- expect(info2.dependencies, contains(dep));
- expect(info2.modificationTimes, hasLength(1));
- expect(info2.modificationTimes, contains(dep));
- expect(info2.modificationTimes[dep], timestamp);
- }
-
- test_computePackageMap_withPreviousInfo_newDependency() {
- String dep = posix.join(projectFolder.path, 'dep');
- resourceProvider.newFile(dep, 'contents').modificationStamp;
- setPubListResult(input_files: []);
- OptimizingPubPackageMapInfo info1 =
- provider.computePackageMap(projectFolder);
- setPubListResult(input_files: [dep]);
- OptimizingPubPackageMapInfo info2 =
- provider.computePackageMap(projectFolder, info1);
- expect(info2.modificationTimes, isEmpty);
- }
-
- test_computePackageMap_withPreviousInfo_oldDependencyNoLongerAFile() {
- String dep = posix.join(projectFolder.path, 'dep');
- resourceProvider.newFile(dep, 'contents').modificationStamp;
- setPubListResult(input_files: [dep]);
- OptimizingPubPackageMapInfo info1 =
- provider.computePackageMap(projectFolder);
- resourceProvider.deleteFile(dep);
- resourceProvider.newFolder(dep);
- OptimizingPubPackageMapInfo info2 =
- provider.computePackageMap(projectFolder, info1);
- expect(info2.modificationTimes, isEmpty);
- }
-
- test_computePackageMap_withPreviousInfo_oldDependencyNoLongerPresent() {
- String dep = posix.join(projectFolder.path, 'dep');
- resourceProvider.newFile(dep, 'contents').modificationStamp;
- setPubListResult(input_files: [dep]);
- OptimizingPubPackageMapInfo info1 =
- provider.computePackageMap(projectFolder);
- resourceProvider.deleteFile(dep);
- OptimizingPubPackageMapInfo info2 =
- provider.computePackageMap(projectFolder, info1);
- expect(info2.modificationTimes, isEmpty);
- }
-
- test_computePackageMap_withPreviousInfo_oldDependencyNoLongerRelevant() {
- String dep = posix.join(projectFolder.path, 'dep');
- resourceProvider.newFile(dep, 'contents').modificationStamp;
- setPubListResult(input_files: [dep]);
- OptimizingPubPackageMapInfo info1 =
- provider.computePackageMap(projectFolder);
- setPubListResult(input_files: []);
- OptimizingPubPackageMapInfo info2 =
- provider.computePackageMap(projectFolder, info1);
- expect(info2.modificationTimes, isEmpty);
- }
-
- test_computePackageMap_withPreviousInfo_pubListError() {
- String dep = posix.join(projectFolder.path, 'dep');
- String pubspecLock = posix.join(projectFolder.path, 'pubspec.lock');
- int timestamp = resourceProvider.newFile(dep, 'contents').modificationStamp;
- setPubListResult(input_files: [dep]);
- OptimizingPubPackageMapInfo info1 =
- provider.computePackageMap(projectFolder);
- setPubListError();
- OptimizingPubPackageMapInfo info2 =
- provider.computePackageMap(projectFolder, info1);
- expect(info2.dependencies, hasLength(2));
- expect(info2.dependencies, contains(dep));
- expect(info2.dependencies, contains(pubspecLock));
- expect(info2.modificationTimes, hasLength(1));
- expect(info2.modificationTimes, contains(dep));
- expect(info2.modificationTimes[dep], timestamp);
- }
-
- io.ProcessResult _runPubList(Folder folder) {
- expect(folder, projectFolder);
- return pubListResult;
- }
-}
-
-class _MockProcessResult implements io.ProcessResult {
- @override
- final int pid;
-
- @override
- final int exitCode;
-
- @override
- final stdout;
-
- @override
- final stderr;
-
- _MockProcessResult(this.pid, this.exitCode, this.stdout, this.stderr);
-}
diff --git a/pkg/analysis_server/test/source/test_all.dart b/pkg/analysis_server/test/source/test_all.dart
index 34a617f..3a3e709 100644
--- a/pkg/analysis_server/test/source/test_all.dart
+++ b/pkg/analysis_server/test/source/test_all.dart
@@ -5,13 +5,10 @@
library test.source;
import 'caching_put_package_map_provider_test.dart' as caching_provider_test;
-import 'optimizing_pub_package_map_provider_test.dart'
- as optimizing_provider_test;
import 'package:unittest/unittest.dart';
/// Utility for manually running all tests.
main() {
groupSep = ' | ';
caching_provider_test.main();
- optimizing_provider_test.main();
}
diff --git a/pkg/analysis_server/test/src/watch_manager_test.dart b/pkg/analysis_server/test/src/watch_manager_test.dart
index 8d1c4e2..a8d885d 100644
--- a/pkg/analysis_server/test/src/watch_manager_test.dart
+++ b/pkg/analysis_server/test/src/watch_manager_test.dart
@@ -96,7 +96,7 @@
await _expectEvent(ChangeType.ADD, newFile1.path, [topToken]);
File newFile2 = provider.newFile('/a/b/c/d/lib.dart', '');
- _expectEvent(ChangeType.ADD, newFile2.path, [topToken, childToken]);
+ return _expectEvent(ChangeType.ADD, newFile2.path, [topToken, childToken]);
}
Future test_addFolder_singleFolder_multipleTokens() {
@@ -119,7 +119,7 @@
await _expectEvent(ChangeType.ADD, newFolder.path, [token]);
File newFile = provider.newFile('/a/b/c/lib.dart', '');
- _expectEvent(ChangeType.ADD, newFile.path, [token]);
+ return _expectEvent(ChangeType.ADD, newFile.path, [token]);
}
Future test_addFolder_unrelatedFolders() async {
@@ -134,7 +134,7 @@
await _expectEvent(ChangeType.ADD, newFile1.path, [token1]);
File newFile2 = provider.newFile('/c/d/lib.dart', '');
- _expectEvent(ChangeType.ADD, newFile2.path, [token2]);
+ return _expectEvent(ChangeType.ADD, newFile2.path, [token2]);
}
void test_creation() {
@@ -153,15 +153,6 @@
return _expectEvent(ChangeType.ADD, newFile.path, [token1]);
}
- Future test_removeFolder_unadded() {
- Folder folder = provider.getFolder('/a/b');
- Token token = new Token('token');
- expect(() => manager.removeFolder(folder, token), throws);
-
- provider.newFile('/a/b/lib.dart', '');
- return _expectNoEvent();
- }
-
Future test_removeFolder_withChildren() async {
Folder topFolder = provider.getFolder('/a/b');
Folder childFolder = provider.getFolder('/a/b/c/d');
@@ -175,7 +166,7 @@
await _expectEvent(ChangeType.ADD, newFile.path, [childToken]);
provider.newFile('/a/b/lib.dart', '');
- _expectNoEvent();
+ return _expectNoEvent();
}
Future test_removeFolder_withNoChildren() {
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index 9307059..77faa63 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -18,6 +18,7 @@
import 'protocol_test.dart' as protocol_test;
import 'search/test_all.dart' as search_all;
import 'services/test_all.dart' as services_all;
+import 'server_options_test.dart' as server_options;
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;
@@ -41,6 +42,7 @@
protocol_server_test.main();
protocol_test.main();
search_all.main();
+ server_options.main();
services_all.main();
socket_server_test.main();
source_all.main();
diff --git a/pkg/analysis_server/tool/spec/codegen_tools.dart b/pkg/analysis_server/tool/spec/codegen_tools.dart
index f388379..078f809 100644
--- a/pkg/analysis_server/tool/spec/codegen_tools.dart
+++ b/pkg/analysis_server/tool/spec/codegen_tools.dart
@@ -102,9 +102,12 @@
}
/**
- * Execute [callback], indenting any code it outputs by two spaces.
+ * Execute [callback], indenting any code it outputs.
*/
- void indent(void callback()) => indentSpecial(' ', ' ', callback);
+ void indent(void callback()) {
+ indentSpecial(codeGeneratorSettings.indent, codeGeneratorSettings.indent,
+ callback);
+ }
/**
* Execute [callback], using [additionalIndent] to indent any code it outputs.
@@ -237,10 +240,15 @@
*/
int commentLineLength;
+ /**
+ * String used for indenting code.
+ */
+ String indent;
+
CodeGeneratorSettings({this.languageName: 'java',
this.lineCommentLineLeader: '// ', this.docCommentStartMarker: '/**',
this.docCommentLineLeader: ' * ', this.docCommentEndMarker: ' */',
- this.commentLineLength: 99});
+ this.commentLineLength: 99, this.indent: ' '});
}
abstract class GeneratedContent {
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index c398e4d..c183dac 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -351,6 +351,23 @@
public void edit_getRefactoring(String kind, String file, int offset, int length, boolean validateOnly, RefactoringOptions options, GetRefactoringConsumer consumer);
/**
+ * {@code edit.organizeDirectives}
+ *
+ * Organizes all of the directives - removes unused imports and sorts directives of the given Dart
+ * file according to the Dart Style Guide.
+ *
+ * If a request is made for a file that does not exist, does not belong to an analysis root or is
+ * not a Dart file, FILE_NOT_ANALYZED will be generated.
+ *
+ * If directives of the Dart file cannot be organized, for example because it has scan or parse
+ * errors, or by other reasons, ORGANIZE_DIRECTIVES_ERROR will be generated. The message will
+ * provide datails about the reason.
+ *
+ * @param file The Dart file to organize directives in.
+ */
+ public void edit_organizeDirectives(String file, OrganizeDirectivesConsumer consumer);
+
+ /**
* {@code edit.sortMembers}
*
* Sort all of the directives, unit and class members of the given Dart file.
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisOptions.java b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisOptions.java
index e46c4813..fa91052 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisOptions.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisOptions.java
@@ -45,27 +45,29 @@
public static final List<AnalysisOptions> EMPTY_LIST = Lists.newArrayList();
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed async feature.
*/
private final Boolean enableAsync;
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed deferred loading feature.
*/
private final Boolean enableDeferredLoading;
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed enum feature.
*/
private final Boolean enableEnums;
/**
+ * Deprecated: this feature is always enabled.
+ *
* True if the client wants to enable support for the proposed "null aware operators" feature.
*/
private final Boolean enableNullAwareOperators;
@@ -139,7 +141,7 @@
}
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed async feature.
*/
@@ -148,7 +150,7 @@
}
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed deferred loading feature.
*/
@@ -157,7 +159,7 @@
}
/**
- * Deprecated
+ * Deprecated: this feature is always enabled.
*
* True if the client wants to enable support for the proposed enum feature.
*/
@@ -166,6 +168,8 @@
}
/**
+ * Deprecated: this feature is always enabled.
+ *
* True if the client wants to enable support for the proposed "null aware operators" feature.
*/
public Boolean getEnableNullAwareOperators() {
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index 8e39aff..a8615d2 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -30,6 +30,12 @@
public static final String CONTENT_MODIFIED = "CONTENT_MODIFIED";
/**
+ * A request specified a FilePath which does not match a file in an analysis root, or the requested
+ * operation is not available for the file.
+ */
+ public static final String FILE_NOT_ANALYZED = "FILE_NOT_ANALYZED";
+
+ /**
* An "edit.format" request specified a FilePath which does not match a Dart file in an analysis
* root.
*/
@@ -47,7 +53,7 @@
public static final String GET_ERRORS_INVALID_FILE = "GET_ERRORS_INVALID_FILE";
/**
- * An "analysis.getErrors" request specified a FilePath which does not match a file currently
+ * An "analysis.getNavigation" request specified a FilePath which does not match a file currently
* subject to analysis.
*/
public static final String GET_NAVIGATION_INVALID_FILE = "GET_NAVIGATION_INVALID_FILE";
@@ -86,6 +92,12 @@
public static final String NO_INDEX_GENERATED = "NO_INDEX_GENERATED";
/**
+ * An "edit.organizeDirectives" request specified a Dart file that cannot be analyzed. The reason
+ * is described in the message.
+ */
+ public static final String ORGANIZE_DIRECTIVES_ERROR = "ORGANIZE_DIRECTIVES_ERROR";
+
+ /**
* Another refactoring request was received during processing of this one.
*/
public static final String REFACTORING_REQUEST_CANCELLED = "REFACTORING_REQUEST_CANCELLED";
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 1d61cb1..6bd7e09 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -1697,6 +1697,41 @@
</field>
</result>
</request>
+ <request method="organizeDirectives">
+ <p>
+ Organizes all of the directives - removes unused imports and sorts
+ directives of the given Dart file according to the
+ <a href="https://www.dartlang.org/articles/style-guide/">Dart Style Guide</a>.
+ </p>
+ <p>
+ If a request is made for a file that does not exist, does not belong
+ to an analysis root or is not a Dart file,
+ <tt>FILE_NOT_ANALYZED</tt> will be generated.
+ </p>
+ <p>
+ If directives of the Dart file cannot be organized, for example
+ because it has scan or parse errors, or by other reasons,
+ <tt>ORGANIZE_DIRECTIVES_ERROR</tt> will be generated. The message
+ will provide datails about the reason.
+ </p>
+ <params>
+ <field name="file">
+ <ref>FilePath</ref>
+ <p>
+ The Dart file to organize directives in.
+ </p>
+ </field>
+ </params>
+ <result>
+ <field name="edit">
+ <ref>SourceFileEdit</ref>
+ <p>
+ The file edit that is to be applied to the given file to effect
+ the organizing.
+ </p>
+ </field>
+ </result>
+ </request>
</domain>
<domain name="execution">
<p>
@@ -1988,7 +2023,7 @@
<object>
<field name="enableAsync" optional="true">
<ref>bool</ref>
- <p><b><i>Deprecated</i></b></p>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed async feature.
@@ -1996,7 +2031,7 @@
</field>
<field name="enableDeferredLoading" optional="true">
<ref>bool</ref>
- <p><b><i>Deprecated</i></b></p>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed deferred loading feature.
@@ -2004,7 +2039,7 @@
</field>
<field name="enableEnums" optional="true">
<ref>bool</ref>
- <p><b><i>Deprecated</i></b></p>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed enum feature.
@@ -2012,6 +2047,7 @@
</field>
<field name="enableNullAwareOperators" optional="true">
<ref>bool</ref>
+ <p><b><i>Deprecated</i></b>: this feature is always enabled.</p>
<p>
True if the client wants to enable support for the
proposed "null aware operators" feature.
@@ -3383,6 +3419,14 @@
</p>
</value>
<value>
+ <code>FILE_NOT_ANALYZED</code>
+ <p>
+ A request specified a FilePath which does not match a file in
+ an analysis root, or the requested operation is not available
+ for the file.
+ </p>
+ </value>
+ <value>
<code>FORMAT_INVALID_FILE</code>
<p>
An "edit.format" request specified a FilePath
@@ -3407,7 +3451,7 @@
<value>
<code>GET_NAVIGATION_INVALID_FILE</code>
<p>
- An "analysis.getErrors" request specified a FilePath
+ An "analysis.getNavigation" request specified a FilePath
which does not match a file currently subject to
analysis.
</p>
@@ -3455,6 +3499,13 @@
</p>
</value>
<value>
+ <code>ORGANIZE_DIRECTIVES_ERROR</code>
+ <p>
+ An "edit.organizeDirectives" request specified a Dart file that
+ cannot be analyzed. The reason is described in the message.
+ </p>
+ </value>
+ <value>
<code>REFACTORING_REQUEST_CANCELLED</code>
<p>
Another refactoring request was received during processing of
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 59a9606..7c67e09 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,23 @@
+## 0.26.0
+
+* No changes from 0.26.0-alpha.2.
+
+## 0.26.0-alpha.2
+
+* Fix highlight range for missing enum constant in switch (issue 23904).
+* Fix analyzer's treatment of `ClassName?.staticMember` to match spec.
+* Implement DEP 34 (less restricted mixins).
+* Fix some implementations of `UriResolver.resolveUri(..)` that did not
+ properly handle the new `actualUri` argument.
+
+## 0.26.0-alpha.1
+
+* Change `ResolutionCopier.visitAwaitExpression` to copy *Type fields.
+
+## 0.26.0-alpha.0
+
+* API change: `UriResolver.resolveUri(..)` now takes an optional `actualUri`.
+
## 0.25.3-alpha.0
* Add hook for listening to implicitly analyzed files
@@ -7,6 +27,7 @@
## 0.25.2
+* Requires Dart SDK 1.12-dev or greater
* Enable null-aware operators (DEP 9) by default.
* Generic method support in the element model.
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 899d6c5..788600b 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -181,14 +181,14 @@
ResourceUriResolver(this._provider);
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (!_isFileUri(uri)) {
return null;
}
Resource resource =
_provider.getResource(_provider.pathContext.fromUri(uri));
if (resource is File) {
- return resource.createSource(uri);
+ return resource.createSource(actualUri != null ? actualUri : uri);
}
return null;
}
diff --git a/pkg/analyzer/lib/source/package_map_resolver.dart b/pkg/analyzer/lib/source/package_map_resolver.dart
index 82000b9..0fa12ae 100644
--- a/pkg/analyzer/lib/source/package_map_resolver.dart
+++ b/pkg/analyzer/lib/source/package_map_resolver.dart
@@ -44,7 +44,7 @@
}
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (!isPackageUri(uri)) {
return null;
}
diff --git a/pkg/analyzer/lib/source/path_filter.dart b/pkg/analyzer/lib/source/path_filter.dart
index 9ee0070..f4123f8 100644
--- a/pkg/analyzer/lib/source/path_filter.dart
+++ b/pkg/analyzer/lib/source/path_filter.dart
@@ -5,16 +5,33 @@
library source.path_filter;
import 'package:glob/glob.dart' as glob;
-import 'package:path/path.dart' as pos;
+import 'package:path/path.dart';
/// Filter paths against a set of [ignorePatterns] relative to a [root]
/// directory. Paths outside of [root] are also ignored.
class PathFilter {
+ /// The path context to use when manipulating paths.
+ final Context pathContext;
+
+ /// Path that all ignore patterns are relative to.
+ final String root;
+
+ /// List of ignore patterns that paths are tested against.
+ final List<glob.Glob> _ignorePatterns = new List<glob.Glob>();
+
/// Construct a new path filter rooted at [root] with [ignorePatterns].
- PathFilter(this.root, List<String> ignorePatterns) {
+ PathFilter(this.pathContext, this.root, List<String> ignorePatterns) {
setIgnorePatterns(ignorePatterns);
}
+ /// Returns true if [path] should be ignored. A path is ignored if it is not
+ /// contained in [root] or matches one of the ignore patterns.
+ /// [path] is absolute or relative to [root].
+ bool ignored(String path) {
+ path = _canonicalize(path);
+ return !_contained(path) || _match(path);
+ }
+
/// Set the ignore patterns.
void setIgnorePatterns(List<String> ignorePatterns) {
_ignorePatterns.clear();
@@ -25,19 +42,9 @@
}
}
- /// Returns true if [path] should be ignored. A path is ignored if it is not
- /// contained in [root] or matches one of the ignore patterns.
- /// [path] is absolute or relative to [root].
- bool ignored(String path) {
- path = _canonicalize(path);
- return !_contained(path) || _match(path);
- }
-
/// Returns the absolute path of [path], relative to [root].
- String _canonicalize(String path) => pos.normalize(pos.join(root, path));
-
- /// Returns the relative portion of [path] from [root].
- String _relative(String path) => pos.relative(path, from:root);
+ String _canonicalize(String path) =>
+ pathContext.normalize(pathContext.join(root, path));
/// Returns true when [path] is contained inside [root].
bool _contained(String path) => path.startsWith(root);
@@ -53,9 +60,15 @@
return false;
}
- /// Path that all ignore patterns are relative to.
- final String root;
+ /// Returns the relative portion of [path] from [root].
+ String _relative(String path) => pathContext.relative(path, from: root);
- /// List of ignore patterns that paths are tested against.
- final List<glob.Glob> _ignorePatterns = new List<glob.Glob>();
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (var pattern in _ignorePatterns) {
+ sb.write('$pattern ');
+ }
+ sb.writeln('');
+ return sb.toString();
+ }
}
diff --git a/pkg/analyzer/lib/source/sdk_ext.dart b/pkg/analyzer/lib/source/sdk_ext.dart
index 696e181..7caad43 100644
--- a/pkg/analyzer/lib/source/sdk_ext.dart
+++ b/pkg/analyzer/lib/source/sdk_ext.dart
@@ -51,7 +51,7 @@
}
@override
- Source resolveAbsolute(Uri importUri) {
+ Source resolveAbsolute(Uri importUri, [Uri actualUri]) {
String libraryName = _libraryName(importUri);
String partPath = _partPath(importUri);
// Lookup library name in mappings.
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 1be6dfb..e48a5cc 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -247,7 +247,9 @@
(this._options.hint && !options.hint) ||
(this._options.lint && !options.lint) ||
this._options.preserveComments != options.preserveComments ||
- this._options.enableStrictCallChecks != options.enableStrictCallChecks;
+ this._options.enableStrictCallChecks !=
+ options.enableStrictCallChecks ||
+ this._options.enableSuperMixins != options.enableSuperMixins;
int cacheSize = options.cacheSize;
if (this._options.cacheSize != cacheSize) {
this._options.cacheSize = cacheSize;
@@ -258,6 +260,7 @@
this._options.generateSdkErrors = options.generateSdkErrors;
this._options.dart2jsHint = options.dart2jsHint;
this._options.enableStrictCallChecks = options.enableStrictCallChecks;
+ this._options.enableSuperMixins = options.enableSuperMixins;
this._options.hint = options.hint;
this._options.incremental = options.incremental;
this._options.incrementalApi = options.incrementalApi;
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index c386c83..f4a8ff3 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -1617,9 +1617,10 @@
@override
VariableDeclarationList visitVariableDeclarationList(
- VariableDeclarationList node) => new VariableDeclarationList(null,
- cloneNodeList(node.metadata), cloneToken(node.keyword),
- cloneNode(node.type), cloneNodeList(node.variables));
+ VariableDeclarationList node) => new VariableDeclarationList(
+ cloneNode(node.documentationComment), cloneNodeList(node.metadata),
+ cloneToken(node.keyword), cloneNode(node.type),
+ cloneNodeList(node.variables));
@override
VariableDeclarationStatement visitVariableDeclarationStatement(
@@ -10841,15 +10842,13 @@
/**
* The value of the literal.
*/
- String _value;
+ String value;
/**
* Initialize a newly created string of characters that are part of a string
* interpolation.
*/
- InterpolationString(this.contents, String value) {
- _value = value;
- }
+ InterpolationString(this.contents, this.value);
@override
Token get beginToken => contents;
@@ -10877,18 +10876,6 @@
@override
Token get endToken => contents;
- /**
- * Return the value of the literal.
- */
- String get value => _value;
-
- /**
- * Set the value of the literal to the given [string].
- */
- void set value(String string) {
- _value = string;
- }
-
@override
accept(AstVisitor visitor) => visitor.visitInterpolationString(this);
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 572caab..742f64d 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -3526,9 +3526,7 @@
}
@deprecated // Use new EvaluationResultImpl(value, errors)
- EvaluationResultImpl.con2(this.value, List<AnalysisError> errors) {
- this._errors = errors;
- }
+ EvaluationResultImpl.con2(this.value, List<AnalysisError> this._errors);
List<AnalysisError> get errors => _errors;
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 395dc27..69beffe 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -85,7 +85,8 @@
@override
bool isMoreSpecificThan(DartType type,
- [bool withDynamic = false, Set<Element> visitedElements]) => true;
+ [bool withDynamic = false, Set<Element> visitedElements]) =>
+ true;
@override
bool isSubtypeOf(DartType type) => true;
@@ -98,8 +99,9 @@
@override
BottomTypeImpl substitute2(
- List<DartType> argumentTypes, List<DartType> parameterTypes,
- [List<FunctionTypeAliasElement> prune]) => this;
+ List<DartType> argumentTypes, List<DartType> parameterTypes,
+ [List<FunctionTypeAliasElement> prune]) =>
+ this;
}
/**
@@ -1154,8 +1156,8 @@
if (definingClass is! ClassElementImpl) {
return null;
}
- getter = (definingClass as ClassElementImpl)._internalLookUpGetter(
- getterName, library, false);
+ getter = (definingClass as ClassElementImpl)
+ ._internalLookUpGetter(getterName, library, false);
}
return getter;
}
@@ -1183,8 +1185,8 @@
if (definingClass is! ClassElementImpl) {
return null;
}
- setter = (definingClass as ClassElementImpl)._internalLookUpSetter(
- setterName, library, false);
+ setter = (definingClass as ClassElementImpl)
+ ._internalLookUpSetter(setterName, library, false);
}
return setter;
}
@@ -2538,6 +2540,8 @@
int get nameOffset;
/**
+ * **DEPRECATED** Use `computeNode()` instead.
+ *
* Return the resolved [AstNode] node that declares this element, or `null` if
* this element is synthetic or isn't contained in a compilation unit, such as
* a [LibraryElement].
@@ -4087,7 +4091,8 @@
* A concrete implementation of a [FieldElement].
*/
class FieldElementImpl extends PropertyInducingElementImpl
- with PotentiallyConstVariableElement implements FieldElement {
+ with PotentiallyConstVariableElement
+ implements FieldElement {
/**
* An empty list of field elements.
*/
@@ -4961,8 +4966,8 @@
DartType type = parameter.type;
if (typeArguments.length != 0 &&
typeArguments.length == typeParameters.length) {
- type = (type as TypeImpl).substitute2(
- typeArguments, typeParameters, newPrune);
+ type = (type as TypeImpl)
+ .substitute2(typeArguments, typeParameters, newPrune);
} else {
type = (type as TypeImpl).pruned(newPrune);
}
@@ -5007,8 +5012,8 @@
DartType type = parameter.type;
if (typeArguments.length != 0 &&
typeArguments.length == typeParameters.length) {
- type = (type as TypeImpl).substitute2(
- typeArguments, typeParameters, newPrune);
+ type = (type as TypeImpl)
+ .substitute2(typeArguments, typeParameters, newPrune);
} else {
type = (type as TypeImpl).pruned(newPrune);
}
@@ -5032,8 +5037,8 @@
DartType type = parameter.type;
if (typeArguments.length != 0 &&
typeArguments.length == typeParameters.length) {
- type = (type as TypeImpl).substitute2(
- typeArguments, typeParameters, newPrune);
+ type = (type as TypeImpl)
+ .substitute2(typeArguments, typeParameters, newPrune);
} else {
type = (type as TypeImpl).pruned(newPrune);
}
@@ -5215,8 +5220,8 @@
return false;
} else if (t.normalParameterTypes.length > 0) {
for (int i = 0; i < tTypes.length; i++) {
- if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
- sTypes[i], withDynamic)) {
+ if (!(tTypes[i] as TypeImpl)
+ .isMoreSpecificThan(sTypes[i], withDynamic)) {
return false;
}
}
@@ -5236,8 +5241,8 @@
if (typeT == null) {
return false;
}
- if (!(typeT as TypeImpl).isMoreSpecificThan(
- namedTypesS[keyS], withDynamic)) {
+ if (!(typeT as TypeImpl)
+ .isMoreSpecificThan(namedTypesS[keyS], withDynamic)) {
return false;
}
}
@@ -5257,8 +5262,8 @@
if (tOpTypes.length == 0 && sOpTypes.length == 0) {
// No positional arguments, don't copy contents to new array
for (int i = 0; i < sTypes.length; i++) {
- if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
- sTypes[i], withDynamic)) {
+ if (!(tTypes[i] as TypeImpl)
+ .isMoreSpecificThan(sTypes[i], withDynamic)) {
return false;
}
}
@@ -5280,8 +5285,8 @@
sAllTypes[i] = sOpTypes[j];
}
for (int i = 0; i < sAllTypes.length; i++) {
- if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan(
- sAllTypes[i], withDynamic)) {
+ if (!(tAllTypes[i] as TypeImpl)
+ .isMoreSpecificThan(sAllTypes[i], withDynamic)) {
return false;
}
}
@@ -6633,8 +6638,8 @@
return false;
}
for (int i = 0; i < tArguments.length; i++) {
- if (!(tArguments[i] as TypeImpl).isMoreSpecificThan(
- sArguments[i], withDynamic)) {
+ if (!(tArguments[i] as TypeImpl)
+ .isMoreSpecificThan(sArguments[i], withDynamic)) {
return false;
}
}
@@ -6664,14 +6669,14 @@
return true;
}
for (InterfaceType interfaceType in interfaces) {
- if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan(
- type, withDynamic, visitedElements)) {
+ if ((interfaceType as InterfaceTypeImpl)
+ .isMoreSpecificThan(type, withDynamic, visitedElements)) {
return true;
}
}
for (InterfaceType mixinType in mixins) {
- if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan(
- type, withDynamic, visitedElements)) {
+ if ((mixinType as InterfaceTypeImpl)
+ .isMoreSpecificThan(type, withDynamic, visitedElements)) {
return true;
}
}
@@ -7645,8 +7650,8 @@
for (ImportElement importElement in _imports) {
LibraryElement importedLibrary = importElement.importedLibrary;
if (importedLibrary != null) {
- (importedLibrary as LibraryElementImpl)._addVisibleLibraries(
- visibleLibraries, true);
+ (importedLibrary as LibraryElementImpl)
+ ._addVisibleLibraries(visibleLibraries, true);
}
}
// add exported libraries
@@ -7654,8 +7659,8 @@
for (ExportElement exportElement in _exports) {
LibraryElement exportedLibrary = exportElement.exportedLibrary;
if (exportedLibrary != null) {
- (exportedLibrary as LibraryElementImpl)._addVisibleLibraries(
- visibleLibraries, true);
+ (exportedLibrary as LibraryElementImpl)
+ ._addVisibleLibraries(visibleLibraries, true);
}
}
}
@@ -7749,7 +7754,8 @@
* A concrete implementation of a [LocalVariableElement].
*/
class LocalVariableElementImpl extends VariableElementImpl
- with PotentiallyConstVariableElement implements LocalVariableElement {
+ with PotentiallyConstVariableElement
+ implements LocalVariableElement {
/**
* An empty list of field elements.
*/
@@ -8659,7 +8665,8 @@
* A concrete implementation of a [ParameterElement].
*/
class ParameterElementImpl extends VariableElementImpl
- with PotentiallyConstVariableElement implements ParameterElement {
+ with PotentiallyConstVariableElement
+ implements ParameterElement {
/**
* An empty list of parameter elements.
*/
@@ -9848,7 +9855,8 @@
* A concrete implementation of a [TopLevelVariableElement].
*/
class TopLevelVariableElementImpl extends PropertyInducingElementImpl
- with PotentiallyConstVariableElement implements TopLevelVariableElement {
+ with PotentiallyConstVariableElement
+ implements TopLevelVariableElement {
/**
* An empty list of top-level variable elements.
*/
@@ -10091,8 +10099,8 @@
}
List<DartType> newTypes = new List<DartType>(length);
for (int i = 0; i < length; i++) {
- newTypes[i] = (types[i] as TypeImpl).substitute2(
- argumentTypes, parameterTypes, prune);
+ newTypes[i] = (types[i] as TypeImpl)
+ .substitute2(argumentTypes, parameterTypes, prune);
}
return newTypes;
}
@@ -10101,7 +10109,7 @@
/**
* A type parameter.
*/
-abstract class TypeParameterElement implements Element {
+abstract class TypeParameterElement implements TypeDefiningElement {
/**
* An empty list of type parameter elements.
*/
@@ -10695,8 +10703,9 @@
@override
VoidTypeImpl substitute2(
- List<DartType> argumentTypes, List<DartType> parameterTypes,
- [List<FunctionTypeAliasElement> prune]) => this;
+ List<DartType> argumentTypes, List<DartType> parameterTypes,
+ [List<FunctionTypeAliasElement> prune]) =>
+ this;
}
/**
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index b93931f..1e5794a 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -608,7 +608,7 @@
// does not apply to conditional method invocation (i.e. 'C?.m(...)').
//
bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
- ClassElementImpl typeReference = getTypeReference(target, isConditional);
+ ClassElementImpl typeReference = getTypeReference(target);
if (typeReference != null) {
staticElement =
propagatedElement = _resolveElement(typeReference, methodName);
@@ -856,7 +856,7 @@
// Otherwise, the prefix is really an expression that happens to be a simple
// identifier and this is really equivalent to a property access node.
//
- _resolvePropertyAccess(prefix, identifier, false);
+ _resolvePropertyAccess(prefix, identifier);
return null;
}
@@ -912,8 +912,7 @@
return null;
}
SimpleIdentifier propertyName = node.propertyName;
- _resolvePropertyAccess(target, propertyName,
- node.operator.type == sc.TokenType.QUESTION_PERIOD);
+ _resolvePropertyAccess(target, propertyName);
return null;
}
@@ -2416,7 +2415,7 @@
}
void _resolvePropertyAccess(
- Expression target, SimpleIdentifier propertyName, bool isConditional) {
+ Expression target, SimpleIdentifier propertyName) {
DartType staticType = _getStaticType(target);
DartType propagatedType = _getPropagatedType(target);
Element staticElement = null;
@@ -2427,7 +2426,7 @@
// hierarchy, instead we just look for the member in the type only. This
// does not apply to conditional property accesses (i.e. 'C?.m').
//
- ClassElementImpl typeReference = getTypeReference(target, isConditional);
+ ClassElementImpl typeReference = getTypeReference(target);
if (typeReference != null) {
// TODO(brianwilkerson) Why are we setting the propagated element here?
// It looks wrong.
@@ -2640,12 +2639,10 @@
/**
* Checks whether the given [expression] is a reference to a class. If it is
* then the element representing the class is returned, otherwise `null` is
- * returned. [isConditional] indicates whether [expression] is to the left
- * of a '?.' opertator.
+ * returned.
*/
- static ClassElementImpl getTypeReference(
- Expression expression, bool isConditional) {
- if (!isConditional && expression is Identifier) {
+ static ClassElementImpl getTypeReference(Expression expression) {
+ if (expression is Identifier) {
Element staticElement = expression.staticElement;
if (staticElement is ClassElementImpl) {
return staticElement;
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 649c2be..5086437 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1118,7 +1118,9 @@
this._options.dart2jsHint != options.dart2jsHint ||
(this._options.hint && !options.hint) ||
this._options.preserveComments != options.preserveComments ||
- this._options.enableStrictCallChecks != options.enableStrictCallChecks;
+ this._options.enableStrictCallChecks !=
+ options.enableStrictCallChecks ||
+ this._options.enableSuperMixins != options.enableSuperMixins;
int cacheSize = options.cacheSize;
if (this._options.cacheSize != cacheSize) {
this._options.cacheSize = cacheSize;
@@ -1144,6 +1146,7 @@
this._options.generateSdkErrors = options.generateSdkErrors;
this._options.dart2jsHint = options.dart2jsHint;
this._options.enableStrictCallChecks = options.enableStrictCallChecks;
+ this._options.enableSuperMixins = options.enableSuperMixins;
this._options.hint = options.hint;
this._options.incremental = options.incremental;
this._options.incrementalApi = options.incrementalApi;
@@ -6149,6 +6152,12 @@
bool get enableStrictCallChecks;
/**
+ * Return `true` if mixins are allowed to inherit from types other than
+ * Object, and are allowed to reference `super`.
+ */
+ bool get enableSuperMixins;
+
+ /**
* Return `true` if errors, warnings and hints should be generated for sources
* that are implicitly being analyzed. The default value is `true`.
*/
@@ -6252,6 +6261,12 @@
bool enableStrictCallChecks = false;
/**
+ * A flag indicating whether mixins are allowed to inherit from types other
+ * than Object, and are allowed to reference `super`.
+ */
+ bool enableSuperMixins = false;
+
+ /**
* A flag indicating whether errors, warnings and hints should be generated
* for sources that are implicitly being analyzed.
*/
@@ -6317,6 +6332,7 @@
cacheSize = options.cacheSize;
dart2jsHint = options.dart2jsHint;
enableStrictCallChecks = options.enableStrictCallChecks;
+ enableSuperMixins = options.enableSuperMixins;
generateImplicitErrors = options.generateImplicitErrors;
generateSdkErrors = options.generateSdkErrors;
hint = options.hint;
@@ -6337,6 +6353,7 @@
cacheSize = options.cacheSize;
dart2jsHint = options.dart2jsHint;
enableStrictCallChecks = options.enableStrictCallChecks;
+ enableSuperMixins = options.enableSuperMixins;
generateImplicitErrors = options.generateImplicitErrors;
generateSdkErrors = options.generateSdkErrors;
hint = options.hint;
@@ -6712,8 +6729,7 @@
* [retentionPolicy] will be used to determine which pieces of data to remove
* from the cache.
*/
- CachePartition(this.context, int maxCacheSize, this._retentionPolicy) {
- this._maxCacheSize = maxCacheSize;
+ CachePartition(this.context, this._maxCacheSize, this._retentionPolicy) {
_recentlyUsed = new List<Source>();
}
@@ -7370,11 +7386,7 @@
/**
* Initialize a newly created pair from the given [library] and [entryPairs].
*/
- CycleBuilder_LibraryPair(ResolvableLibrary library,
- List<CycleBuilder_SourceEntryPair> entryPairs) {
- this.library = library;
- this.entryPairs = entryPairs;
- }
+ CycleBuilder_LibraryPair(this.library, this.entryPairs);
}
/**
@@ -7396,10 +7408,7 @@
/**
* Initialize a newly created pair from the given [source] and [entry].
*/
- CycleBuilder_SourceEntryPair(Source source, DartEntry entry) {
- this.source = source;
- this.entry = entry;
- }
+ CycleBuilder_SourceEntryPair(this.source, this.entry);
}
/**
@@ -8397,7 +8406,8 @@
// Use the ErrorVerifier to compute the rest of the errors.
//
ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter,
- libraryElement, typeProvider, new InheritanceManager(libraryElement));
+ libraryElement, typeProvider, new InheritanceManager(libraryElement),
+ context.analysisOptions.enableSuperMixins);
_unit.accept(errorVerifier);
_errors = errorListener.getErrorsForSource(source);
});
@@ -8956,13 +8966,8 @@
int _newLength = 0;
IncrementalAnalysisCache(this.librarySource, this.source, this.resolvedUnit,
- this.oldContents, String newContents, int offset, int oldLength,
- int newLength) {
- this._newContents = newContents;
- this._offset = offset;
- this._oldLength = oldLength;
- this._newLength = newLength;
- }
+ this.oldContents, this._newContents, this._offset, this._oldLength,
+ this._newLength);
/**
* Determine if the cache contains source changes that need to be analyzed
@@ -10832,8 +10837,9 @@
//
PerformanceStatistics.errors.makeCurrentWhile(() {
ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
- ErrorVerifier errorVerifier = new ErrorVerifier(
- errorReporter, _libraryElement, typeProvider, inheritanceManager);
+ ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter,
+ _libraryElement, typeProvider, inheritanceManager,
+ context.analysisOptions.enableSuperMixins);
unit.accept(errorVerifier);
// TODO(paulberry): as a temporary workaround for issue 21572,
// ConstantVerifier is being run right after ConstantValueComputer, so we
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index c667af7..0964a8c 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -40,9 +40,9 @@
ErrorCode errorCode2 = o2.errorCode;
ErrorSeverity errorSeverity1 = errorCode1.errorSeverity;
ErrorSeverity errorSeverity2 = errorCode2.errorSeverity;
- ErrorType errorType1 = errorCode1.type;
- ErrorType errorType2 = errorCode2.type;
if (errorSeverity1 == errorSeverity2) {
+ ErrorType errorType1 = errorCode1.type;
+ ErrorType errorType2 = errorCode2.type;
return errorType1.compareTo(errorType2);
} else {
return errorSeverity2.compareTo(errorSeverity1);
@@ -80,7 +80,7 @@
* The number of characters from the offset to the end of the source which
* encompasses the compilation error.
*/
- int _length = 0;
+ int length = 0;
/**
* A flag indicating whether this error can be shown to be a non-issue because
@@ -94,9 +94,8 @@
* [length]. The error will have the given [errorCode] and the list of
* [arguments] will be used to complete the message.
*/
- AnalysisError(this.source, this.offset, int length, this.errorCode,
+ AnalysisError(this.source, this.offset, this.length, this.errorCode,
[List<Object> arguments]) {
- this._length = length;
this._message = formatList(errorCode.message, arguments);
String correctionTemplate = errorCode.correction;
if (correctionTemplate != null) {
@@ -141,13 +140,6 @@
}
/**
- * Return the length of the error location, that is, the number of characters
- * from the offset to the end of the source which encompasses the compilation
- * error.
- */
- int get length => _length;
-
- /**
* Return the message to be displayed for this error. The message should
* indicate what is wrong and why it is wrong.
*/
@@ -167,7 +159,7 @@
if (!identical(errorCode, other.errorCode)) {
return false;
}
- if (offset != other.offset || _length != other._length) {
+ if (offset != other.offset || length != other.length) {
return false;
}
if (isStaticOnly != other.isStaticOnly) {
@@ -197,7 +189,7 @@
buffer.write("(");
buffer.write(offset);
buffer.write("..");
- buffer.write(offset + _length - 1);
+ buffer.write(offset + length - 1);
buffer.write("): ");
//buffer.write("(" + lineNumber + ":" + columnNumber + "): ");
buffer.write(_message);
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index e80e02a..9e25a85 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -255,10 +255,16 @@
List<InterfaceType> _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT;
/**
+ * If `true`, mixins are allowed to inherit from types other than Object, and
+ * are allowed to reference `super`.
+ */
+ final bool enableSuperMixins;
+
+ /**
* Initialize a newly created error verifier.
*/
ErrorVerifier(this._errorReporter, this._currentLibrary, this._typeProvider,
- this._inheritanceManager) {
+ this._inheritanceManager, this.enableSuperMixins) {
this._isInSystemLibrary = _currentLibrary.source.isInSystemLibrary;
this._hasExtUri = _currentLibrary.hasExtUri;
_isEnclosingConstructorConst = false;
@@ -859,9 +865,7 @@
Expression target = node.realTarget;
SimpleIdentifier methodName = node.methodName;
if (target != null) {
- bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
- ClassElement typeReference =
- ElementResolver.getTypeReference(target, isConditional);
+ ClassElement typeReference = ElementResolver.getTypeReference(target);
_checkForStaticAccessToInstanceMember(typeReference, methodName);
_checkForInstanceAccessToStaticMember(typeReference, methodName);
} else {
@@ -898,7 +902,7 @@
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
if (node.parent is! Annotation) {
ClassElement typeReference =
- ElementResolver.getTypeReference(node.prefix, false);
+ ElementResolver.getTypeReference(node.prefix);
SimpleIdentifier name = node.identifier;
_checkForStaticAccessToInstanceMember(typeReference, name);
_checkForInstanceAccessToStaticMember(typeReference, name);
@@ -923,7 +927,7 @@
Object visitPropertyAccess(PropertyAccess node) {
bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
ClassElement typeReference =
- ElementResolver.getTypeReference(node.realTarget, isConditional);
+ ElementResolver.getTypeReference(node.realTarget);
SimpleIdentifier propertyName = node.propertyName;
_checkForStaticAccessToInstanceMember(typeReference, propertyName);
_checkForInstanceAccessToStaticMember(typeReference, propertyName);
@@ -1653,7 +1657,8 @@
if (_checkForMixinDeclaresConstructor(mixinName, mixinElement)) {
problemReported = true;
}
- if (_checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
+ if (!enableSuperMixins &&
+ _checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
problemReported = true;
}
if (_checkForMixinReferencesSuper(mixinName, mixinElement)) {
@@ -4113,9 +4118,11 @@
return false;
}
for (int i = 0; i < nameCount; i++) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH, statement,
- [constantNames[i]]);
+ int offset = statement.offset;
+ int end = statement.rightParenthesis.end;
+ _errorReporter.reportErrorForOffset(
+ CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH, offset,
+ end - offset, [constantNames[i]]);
}
return true;
}
@@ -4209,7 +4216,7 @@
*/
bool _checkForMixinReferencesSuper(
TypeName mixinName, ClassElement mixinElement) {
- if (mixinElement.hasReferenceToSuper) {
+ if (!enableSuperMixins && mixinElement.hasReferenceToSuper) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.MIXIN_REFERENCES_SUPER, mixinName,
[mixinElement.name]);
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index 99b0d51..3bccaab 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -1160,11 +1160,7 @@
int length = 0;
- XmlExpression_Reference(Element element, int offset, int length) {
- this.element = element;
- this.offset = offset;
- this.length = length;
- }
+ XmlExpression_Reference(this.element, this.offset, this.length);
}
/**
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 78481ce..2fcef7b 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -23,7 +23,7 @@
VERIFY_ERRORS;
import 'package:analyzer/task/dart.dart'
show DART_ERRORS, LibrarySpecificUnit, PARSED_UNIT, TOKEN_STREAM;
-import 'package:analyzer/task/general.dart' show CONTENT;
+import 'package:analyzer/task/general.dart' show CONTENT, LINE_INFO;
import 'package:analyzer/task/model.dart' show ResultDescriptor;
import 'ast.dart';
@@ -1233,7 +1233,8 @@
ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter,
_definingLibrary, _typeProvider,
- new InheritanceManager(_definingLibrary));
+ new InheritanceManager(_definingLibrary),
+ _context.analysisOptions.enableSuperMixins);
if (_resolutionContext.enclosingClassDeclaration != null) {
errorVerifier.visitClassDeclarationIncrementally(
_resolutionContext.enclosingClassDeclaration);
@@ -1274,6 +1275,7 @@
int _updateEndOld;
int _updateEndNew;
+ LineInfo _newLineInfo;
List<AnalysisError> _newScanErrors = <AnalysisError>[];
List<AnalysisError> _newParseErrors = <AnalysisError>[];
@@ -1508,6 +1510,7 @@
CharSequenceReader reader = new CharSequenceReader(code);
Scanner scanner = new Scanner(_unitSource, reader, errorListener);
Token token = scanner.tokenize();
+ _newLineInfo = new LineInfo(scanner.lineStarts);
_newScanErrors = errorListener.errors;
return token;
}
@@ -1564,6 +1567,7 @@
_newSourceEntry.setState(SCAN_ERRORS, CacheState.INVALID);
List<TargetedResult> scanDeps =
<TargetedResult>[new TargetedResult(_unitSource, CONTENT)];
+ _newSourceEntry.setValue(LINE_INFO, _newLineInfo, scanDeps);
_newSourceEntry.setValue(SCAN_ERRORS, _newScanErrors, scanDeps);
// parse results
List<TargetedResult> parseDeps =
@@ -1574,6 +1578,7 @@
}
void _updateEntry_OLD() {
+ _oldEntry.setValue(SourceEntry.LINE_INFO, _newLineInfo);
_oldEntry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors);
_oldEntry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors);
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 8581fa4..df3187b 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -9428,8 +9428,13 @@
@override
bool visitAwaitExpression(AwaitExpression node) {
AwaitExpression toNode = this._toNode as AwaitExpression;
- return _and(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword),
- _isEqualNodes(node.expression, toNode.expression));
+ if (_and(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword),
+ _isEqualNodes(node.expression, toNode.expression))) {
+ toNode.propagatedType = node.propagatedType;
+ toNode.staticType = node.staticType;
+ return true;
+ }
+ return false;
}
@override
@@ -10033,12 +10038,16 @@
@override
bool visitLibraryDirective(LibraryDirective node) {
LibraryDirective toNode = this._toNode as LibraryDirective;
- return _and(
+ if (_and(
_isEqualNodes(node.documentationComment, toNode.documentationComment),
_isEqualNodeLists(node.metadata, toNode.metadata),
_isEqualTokens(node.libraryKeyword, toNode.libraryKeyword),
_isEqualNodes(node.name, toNode.name),
- _isEqualTokens(node.semicolon, toNode.semicolon));
+ _isEqualTokens(node.semicolon, toNode.semicolon))) {
+ toNode.element = node.element;
+ return true;
+ }
+ return false;
}
@override
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 49fc6c7..8110c8c 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -293,9 +293,12 @@
* @return `true` if and only if an hint code is generated on the passed node
* See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
*/
- bool _checkForArgumentTypeNotAssignable(Expression expression,
- DartType expectedStaticType, DartType actualStaticType,
- DartType expectedPropagatedType, DartType actualPropagatedType,
+ bool _checkForArgumentTypeNotAssignable(
+ Expression expression,
+ DartType expectedStaticType,
+ DartType actualStaticType,
+ DartType expectedPropagatedType,
+ DartType actualPropagatedType,
ErrorCode hintCode) {
//
// Warning case: test static type information
@@ -347,8 +350,10 @@
DartType propagatedParameterType = propagatedParameterElement == null
? null
: propagatedParameterElement.type;
- return _checkForArgumentTypeNotAssignableWithExpectedTypes(argument,
- staticParameterType, propagatedParameterType,
+ return _checkForArgumentTypeNotAssignableWithExpectedTypes(
+ argument,
+ staticParameterType,
+ propagatedParameterType,
HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE);
}
@@ -364,11 +369,17 @@
* See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
*/
bool _checkForArgumentTypeNotAssignableWithExpectedTypes(
- Expression expression, DartType expectedStaticType,
- DartType expectedPropagatedType, ErrorCode errorCode) =>
- _checkForArgumentTypeNotAssignable(expression, expectedStaticType,
- expression.staticType, expectedPropagatedType,
- expression.propagatedType, errorCode);
+ Expression expression,
+ DartType expectedStaticType,
+ DartType expectedPropagatedType,
+ ErrorCode errorCode) =>
+ _checkForArgumentTypeNotAssignable(
+ expression,
+ expectedStaticType,
+ expression.staticType,
+ expectedPropagatedType,
+ expression.propagatedType,
+ errorCode);
/**
* This verifies that the passed arguments can be assigned to their corresponding parameters.
@@ -541,7 +552,8 @@
}
if (importedLibrary.hasLoadLibraryFunction) {
_errorReporter.reportErrorForNode(
- HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION, node,
+ HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION,
+ node,
[importedLibrary.name]);
return true;
}
@@ -740,12 +752,16 @@
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,
+ return new AnalysisError(
+ duplicate.source,
+ duplicate.nameOffset,
duplicate.displayName.length,
CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
[existing.displayName]);
} else {
- return new AnalysisError(existing.source, existing.nameOffset,
+ return new AnalysisError(
+ existing.source,
+ existing.nameOffset,
existing.displayName.length,
CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
[existing.displayName]);
@@ -919,8 +935,11 @@
new ConstantEvaluationEngine(_typeProvider, declaredVariables);
ConstantVisitor constantVisitor =
new ConstantVisitor(evaluationEngine, _errorReporter);
- evaluationEngine.evaluateConstructorCall(node,
- node.argumentList.arguments, constructor, constantVisitor,
+ evaluationEngine.evaluateConstructorCall(
+ node,
+ node.argumentList.arguments,
+ constructor,
+ constantVisitor,
_errorReporter);
}
}
@@ -976,7 +995,8 @@
if (_implementsEqualsWhenNotAllowed(type)) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
- key, [type.displayName]);
+ key,
+ [type.displayName]);
}
}
} else {
@@ -1040,7 +1060,8 @@
if (firstType != nType) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES,
- expression, [expression.toSource(), firstType.displayName]);
+ expression,
+ [expression.toSource(), firstType.displayName]);
foundError = true;
}
}
@@ -1093,7 +1114,8 @@
// report error
_errorReporter.reportErrorForToken(
CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
- node.switchKeyword, [type.displayName]);
+ node.switchKeyword,
+ [type.displayName]);
return true;
}
@@ -1299,11 +1321,13 @@
new ErrorReporter(errorListener, _errorReporter.source);
DartObjectImpl result = initializer.accept(new ConstantVisitor(
new ConstantEvaluationEngine(
- _typeProvider, declaredVariables), subErrorReporter));
+ _typeProvider, declaredVariables),
+ subErrorReporter));
if (result == null) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
- errorSite, [variableDeclaration.name.name]);
+ errorSite,
+ [variableDeclaration.name.name]);
}
}
}
@@ -1625,10 +1649,10 @@
int offset = catchClause.offset;
int length = lastCatchClause.end - offset;
_errorReporter.reportErrorForOffset(
- HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, offset, length, [
- currentType.displayName,
- type.displayName
- ]);
+ HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
+ offset,
+ length,
+ [currentType.displayName, type.displayName]);
return null;
}
}
@@ -1925,9 +1949,10 @@
String uri = _getStringValue(node.uri);
if (uri != null) {
LibraryElement library = _enclosingUnit.library;
- ExportElement exportElement = _findExport(library.exports,
- _enclosingUnit.context.sourceFactory.resolveUri(
- _enclosingUnit.source, uri));
+ ExportElement exportElement = _findExport(
+ library.exports,
+ _enclosingUnit.context.sourceFactory
+ .resolveUri(_enclosingUnit.source, uri));
node.element = exportElement;
}
return super.visitExportDirective(node);
@@ -2031,9 +2056,11 @@
String uri = _getStringValue(node.uri);
if (uri != null) {
LibraryElement library = _enclosingUnit.library;
- ImportElement importElement = _findImport(library.imports,
- _enclosingUnit.context.sourceFactory.resolveUri(
- _enclosingUnit.source, uri), node.prefix);
+ ImportElement importElement = _findImport(
+ library.imports,
+ _enclosingUnit.context.sourceFactory
+ .resolveUri(_enclosingUnit.source, uri),
+ node.prefix);
node.element = importElement;
}
return super.visitImportDirective(node);
@@ -2084,8 +2111,8 @@
Object visitPartDirective(PartDirective node) {
String uri = _getStringValue(node.uri);
if (uri != null) {
- Source partSource = _enclosingUnit.context.sourceFactory.resolveUri(
- _enclosingUnit.source, uri);
+ Source partSource = _enclosingUnit.context.sourceFactory
+ .resolveUri(_enclosingUnit.source, uri);
node.element = _findPart(_enclosingUnit.library.parts, partSource);
}
return super.visitPartDirective(node);
@@ -3012,8 +3039,8 @@
} else {
String message =
"Exception caught in ElementBuilder.visitMethodDeclaration()";
- AnalysisEngine.instance.logger.logError(
- message, new CaughtException(exception, stackTrace));
+ AnalysisEngine.instance.logger
+ .logError(message, new CaughtException(exception, stackTrace));
}
} finally {
if (node.name.staticElement == null) {
@@ -3025,7 +3052,8 @@
buffer.write(" in ");
buffer.write(classNode.name);
buffer.write(" was not set while trying to resolve types.");
- AnalysisEngine.instance.logger.logError(buffer.toString(),
+ AnalysisEngine.instance.logger.logError(
+ buffer.toString(),
new CaughtException(
new AnalysisException(buffer.toString()), null));
}
@@ -3726,8 +3754,10 @@
if (_hasHiddenName) {
Element hiddenElement = _hiddenElements[name];
if (hiddenElement != null) {
- errorListener.onError(new AnalysisError(getSource(identifier),
- identifier.offset, identifier.length,
+ errorListener.onError(new AnalysisError(
+ getSource(identifier),
+ identifier.offset,
+ identifier.length,
CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
return hiddenElement;
}
@@ -4758,12 +4788,7 @@
* @param classToTagsMap a table mapping the classes defined in the HTML file to an array
* containing the names of tags with that class
*/
- HtmlTagInfo(List<String> allTags, HashMap<String, String> idToTagMap,
- HashMap<String, List<String>> classToTagsMap) {
- this.allTags = allTags;
- this.idToTagMap = idToTagMap;
- this.classToTagsMap = classToTagsMap;
- }
+ HtmlTagInfo(this.allTags, this.idToTagMap, this.classToTagsMap);
/**
* Return an array containing the tags that have the given class, or {@code null} if there are no
@@ -5678,7 +5703,8 @@
* @return the passed function type with any parameterized types substituted
*/
FunctionType substituteTypeArgumentsInMemberFromInheritance(
- FunctionType baseFunctionType, String memberName,
+ FunctionType baseFunctionType,
+ String memberName,
InterfaceType definingType) {
// if the baseFunctionType is null, or does not have any parameters,
// return it.
@@ -6235,12 +6261,12 @@
if (!classHasMember) {
String firstTwoFuntionTypesStr =
"${executableElementTypes[0]}, ${executableElementTypes[1]}";
- _reportError(classElt, classElt.nameOffset,
+ _reportError(
+ classElt,
+ classElt.nameOffset,
classElt.displayName.length,
- StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [
- key,
- firstTwoFuntionTypesStr
- ]);
+ StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
+ [key, firstTwoFuntionTypesStr]);
}
} else {
//
@@ -6252,9 +6278,8 @@
// Tests: test_getMapOfMembersInheritedFromInterfaces_
// union_multipleSubtypes_*
//
- List<ExecutableElement> elementArrayToMerge =
- new List<ExecutableElement>(
- subtypesOfAllOtherTypesIndexes.length);
+ List<ExecutableElement> elementArrayToMerge = new List<
+ ExecutableElement>(subtypesOfAllOtherTypesIndexes.length);
for (int i = 0; i < elementArrayToMerge.length; i++) {
elementArrayToMerge[i] =
elements[subtypesOfAllOtherTypesIndexes[i]];
@@ -6265,7 +6290,9 @@
}
}
} else {
- _reportError(classElt, classElt.nameOffset,
+ _reportError(
+ classElt,
+ classElt.nameOffset,
classElt.displayName.length,
StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD,
[key]);
@@ -6388,8 +6415,11 @@
}
namedParametersList.addAll(_getNamedParameterNames(element));
}
- return _createSyntheticExecutableElement(elementArrayToMerge,
- elementArrayToMerge[0].displayName, r, h - r,
+ return _createSyntheticExecutableElement(
+ elementArrayToMerge,
+ elementArrayToMerge[0].displayName,
+ r,
+ h - r,
new List.from(namedParametersList));
}
@@ -6405,8 +6435,10 @@
* @return the created synthetic element
*/
static ExecutableElement _createSyntheticExecutableElement(
- List<ExecutableElement> elementArrayToMerge, String name,
- int numOfRequiredParameters, int numOfPositionalParameters,
+ List<ExecutableElement> elementArrayToMerge,
+ String name,
+ int numOfRequiredParameters,
+ int numOfPositionalParameters,
List<String> namedParameters) {
DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
SimpleIdentifier nameIdentifier = new SimpleIdentifier(
@@ -6788,8 +6820,8 @@
LibraryElementImpl get libraryElement {
if (_libraryElement == null) {
try {
- _libraryElement = _analysisContext
- .computeLibraryElement(librarySource) as LibraryElementImpl;
+ _libraryElement = _analysisContext.computeLibraryElement(librarySource)
+ as LibraryElementImpl;
} on AnalysisException catch (exception, stackTrace) {
AnalysisEngine.instance.logger.logError(
"Could not compute library element for ${librarySource.fullName}",
@@ -6866,9 +6898,12 @@
Source source =
_analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
if (!_analysisContext.exists(source)) {
- errorListener.onError(new AnalysisError(librarySource,
- uriLiteral.offset, uriLiteral.length,
- CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent]));
+ errorListener.onError(new AnalysisError(
+ librarySource,
+ uriLiteral.offset,
+ uriLiteral.length,
+ CompileTimeErrorCode.URI_DOES_NOT_EXIST,
+ [uriContent]));
}
return source;
} on URISyntaxException {
@@ -6973,21 +7008,24 @@
String partLibraryName =
_getPartLibraryName(partSource, partUnit, directivesToResolve);
if (partLibraryName == null) {
- _errorListener.onError(new AnalysisError(librarySource,
- partUri.offset, partUri.length,
- CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()]));
+ _errorListener.onError(new AnalysisError(
+ librarySource,
+ partUri.offset,
+ partUri.length,
+ CompileTimeErrorCode.PART_OF_NON_PART,
+ [partUri.toSource()]));
} else if (libraryNameNode == null) {
// TODO(brianwilkerson) Collect the names declared by the part.
// If they are all the same then we can use that name as the
// inferred name of the library and present it in a quick-fix.
// partLibraryNames.add(partLibraryName);
} else if (libraryNameNode.name != partLibraryName) {
- _errorListener.onError(new AnalysisError(librarySource,
- partUri.offset, partUri.length,
- StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [
- libraryNameNode.name,
- partLibraryName
- ]));
+ _errorListener.onError(new AnalysisError(
+ librarySource,
+ partUri.offset,
+ partUri.length,
+ StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
+ [libraryNameNode.name, partLibraryName]));
}
if (entryPoint == null) {
entryPoint = _findEntryPoint(part);
@@ -7077,21 +7115,24 @@
String partLibraryName =
_getPartLibraryName(partSource, partUnit, directivesToResolve);
if (partLibraryName == null) {
- _errorListener.onError(new AnalysisError(librarySource,
- partUri.offset, partUri.length,
- CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()]));
+ _errorListener.onError(new AnalysisError(
+ librarySource,
+ partUri.offset,
+ partUri.length,
+ CompileTimeErrorCode.PART_OF_NON_PART,
+ [partUri.toSource()]));
} else if (libraryNameNode == null) {
// TODO(brianwilkerson) Collect the names declared by the part.
// If they are all the same then we can use that name as the
// inferred name of the library and present it in a quick-fix.
// partLibraryNames.add(partLibraryName);
} else if (libraryNameNode.name != partLibraryName) {
- _errorListener.onError(new AnalysisError(librarySource,
- partUri.offset, partUri.length,
- StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [
- libraryNameNode.name,
- partLibraryName
- ]));
+ _errorListener.onError(new AnalysisError(
+ librarySource,
+ partUri.offset,
+ partUri.length,
+ StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
+ [libraryNameNode.name, partLibraryName]));
}
if (entryPoint == null) {
entryPoint = _findEntryPoint(part);
@@ -7296,8 +7337,10 @@
libraryNames[i] = _getLibraryName(conflictingMembers[i]);
}
libraryNames.sort();
- errorListener.onError(new AnalysisError(getSource(identifier),
- identifier.offset, identifier.length,
+ errorListener.onError(new AnalysisError(
+ getSource(identifier),
+ identifier.offset,
+ identifier.length,
StaticWarningCode.AMBIGUOUS_IMPORT, [
foundEltName,
StringUtilities.printListOfQuotedNames(libraryNames)
@@ -7398,13 +7441,12 @@
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
- ]));
+ 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
@@ -7753,7 +7795,8 @@
* @param visitedLibraries the libraries that have already been visited, used to prevent infinite
* recursion
*/
- void _addToDependencyMap(Library library,
+ void _addToDependencyMap(
+ Library library,
HashMap<Library, List<Library>> dependencyMap,
Set<Library> visitedLibraries) {
if (visitedLibraries.add(library)) {
@@ -7858,8 +7901,11 @@
ErrorCode errorCode = (importElement.isDeferred
? StaticWarningCode.IMPORT_OF_NON_LIBRARY
: CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
- _errorListener.onError(new AnalysisError(library.librarySource,
- uriLiteral.offset, uriLiteral.length, errorCode,
+ _errorListener.onError(new AnalysisError(
+ library.librarySource,
+ uriLiteral.offset,
+ uriLiteral.length,
+ errorCode,
[uriLiteral.toSource()]));
}
}
@@ -7888,8 +7934,10 @@
exports.add(exportElement);
if (analysisContext.computeKindOf(exportedSource) !=
SourceKind.LIBRARY) {
- _errorListener.onError(new AnalysisError(library.librarySource,
- uriLiteral.offset, uriLiteral.length,
+ _errorListener.onError(new AnalysisError(
+ library.librarySource,
+ uriLiteral.offset,
+ uriLiteral.length,
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
[uriLiteral.toSource()]));
}
@@ -8046,7 +8094,8 @@
*/
void _computeLibraryDependencies(Library library) {
Source librarySource = library.librarySource;
- _computeLibraryDependenciesFromDirectives(library,
+ _computeLibraryDependenciesFromDirectives(
+ library,
analysisContext.computeImportedLibraries(librarySource),
analysisContext.computeExportedLibraries(librarySource));
}
@@ -8200,7 +8249,9 @@
ErrorReporter errorReporter =
new ErrorReporter(_errorListener, source);
ConstantVerifier constantVerifier = new ConstantVerifier(
- errorReporter, library.libraryElement, _typeProvider,
+ errorReporter,
+ library.libraryElement,
+ _typeProvider,
analysisContext.declaredVariables);
unit.accept(constantVerifier);
} on AnalysisException catch (exception, stackTrace) {
@@ -8503,8 +8554,11 @@
ErrorCode errorCode = (importElement.isDeferred
? StaticWarningCode.IMPORT_OF_NON_LIBRARY
: CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
- _errorListener.onError(new AnalysisError(library.librarySource,
- uriLiteral.offset, uriLiteral.length, errorCode,
+ _errorListener.onError(new AnalysisError(
+ library.librarySource,
+ uriLiteral.offset,
+ uriLiteral.length,
+ errorCode,
[uriLiteral.toSource()]));
}
}
@@ -8536,8 +8590,10 @@
exports.add(exportElement);
if (analysisContext.computeKindOf(exportedSource) !=
SourceKind.LIBRARY) {
- _errorListener.onError(new AnalysisError(library.librarySource,
- uriLiteral.offset, uriLiteral.length,
+ _errorListener.onError(new AnalysisError(
+ library.librarySource,
+ uriLiteral.offset,
+ uriLiteral.length,
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
[uriLiteral.toSource()]));
}
@@ -8631,7 +8687,9 @@
Source source = unit.source;
CompilationUnit ast = unit.compilationUnit;
TypeResolverVisitor visitor = new TypeResolverVisitor(
- library.libraryElement, source, _typeProvider,
+ library.libraryElement,
+ source,
+ _typeProvider,
library.libraryScope.errorListener,
nameScope: library.libraryScope);
ast.accept(visitor);
@@ -8681,7 +8739,9 @@
ErrorReporter errorReporter =
new ErrorReporter(_errorListener, unit.source);
ConstantVerifier constantVerifier = new ConstantVerifier(
- errorReporter, library.libraryElement, _typeProvider,
+ errorReporter,
+ library.libraryElement,
+ _typeProvider,
analysisContext.declaredVariables);
ast.accept(constantVerifier);
}
@@ -8819,7 +8879,9 @@
offset = accessor.variable.nameOffset;
}
}
- return new AnalysisError(duplicate.source, offset,
+ return new AnalysisError(
+ duplicate.source,
+ offset,
duplicate.displayName.length,
CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
[existing.displayName]);
@@ -9301,7 +9363,8 @@
definedNames.addAll(exportedNames);
}
}
- _addAllFromNamespace(definedNames,
+ _addAllFromNamespace(
+ definedNames,
(library.context as InternalAnalysisContext)
.getPublicNamespace(library));
return definedNames;
@@ -10025,10 +10088,11 @@
*/
ResolverVisitor(LibraryElement definingLibrary, Source source,
TypeProvider typeProvider, AnalysisErrorListener errorListener,
- {Scope nameScope, InheritanceManager inheritanceManager,
+ {Scope nameScope,
+ InheritanceManager inheritanceManager,
StaticTypeAnalyzerFactory typeAnalyzerFactory})
: super(definingLibrary, source, typeProvider, errorListener,
- nameScope: nameScope) {
+ nameScope: nameScope) {
if (inheritanceManager == null) {
this._inheritanceManager = new InheritanceManager(definingLibrary);
} else {
@@ -10056,10 +10120,10 @@
Library library, Source source, TypeProvider typeProvider,
{StaticTypeAnalyzerFactory typeAnalyzerFactory})
: this(
- library.libraryElement, source, typeProvider, library.errorListener,
- nameScope: library.libraryScope,
- inheritanceManager: library.inheritanceManager,
- typeAnalyzerFactory: typeAnalyzerFactory);
+ library.libraryElement, source, typeProvider, library.errorListener,
+ nameScope: library.libraryScope,
+ inheritanceManager: library.inheritanceManager,
+ typeAnalyzerFactory: typeAnalyzerFactory);
/**
* Return the element representing the function containing the current node, or `null` if
@@ -10715,9 +10779,16 @@
if (loopVariable != null && iterable != null) {
LocalVariableElement loopElement = loopVariable.element;
if (loopElement != null) {
- DartType iteratorElementType = _getIteratorElementType(iterable);
- overrideVariable(loopElement, iteratorElementType, true);
- _recordPropagatedType(loopVariable.identifier, iteratorElementType);
+ DartType propagatedType = null;
+ if (node.awaitKeyword == null) {
+ propagatedType = _getIteratorElementType(iterable);
+ } else {
+ propagatedType = _getStreamElementType(iterable);
+ }
+ if (propagatedType != null) {
+ overrideVariable(loopElement, propagatedType, true);
+ _recordPropagatedType(loopVariable.identifier, propagatedType);
+ }
}
} else if (identifier != null && iterable != null) {
Element identifierElement = identifier.staticElement;
@@ -11099,12 +11170,11 @@
}
/**
- * The given expression is the expression used to compute the iterator for a for-each statement.
- * Attempt to compute the type of objects that will be assigned to the loop variable and return
- * that type. Return `null` if the type could not be determined.
- *
- * @param iterator the iterator for a for-each statement
- * @return the type of objects that will be assigned to the loop variable
+ * The given expression is the expression used to compute the iterator for a
+ * for-each statement. Attempt to compute the type of objects that will be
+ * assigned to the loop variable and return that type. Return `null` if the
+ * type could not be determined. The [iteratorExpression] is the expression
+ * that will return the Iterable being iterated over.
*/
DartType _getIteratorElementType(Expression iteratorExpression) {
DartType expressionType = iteratorExpression.bestType;
@@ -11132,6 +11202,40 @@
}
/**
+ * The given expression is the expression used to compute the stream for an
+ * asyncronous for-each statement. Attempt to compute the type of objects that
+ * will be assigned to the loop variable and return that type. Return `null`
+ * if the type could not be determined. The [streamExpression] is the
+ * expression that will return the stream being iterated over.
+ */
+ DartType _getStreamElementType(Expression streamExpression) {
+ DartType streamType = streamExpression.bestType;
+ if (streamType is InterfaceType) {
+ FunctionType listenFunction =
+ _inheritanceManager.lookupMemberType(streamType, "listen");
+ if (listenFunction == null) {
+ return null;
+ }
+ List<ParameterElement> listenParameters = listenFunction.parameters;
+ if (listenParameters == null || listenParameters.length < 1) {
+ return null;
+ }
+ DartType onDataType = listenParameters[0].type;
+ if (onDataType is FunctionType) {
+ List<ParameterElement> onDataParameters = onDataType.parameters;
+ if (onDataParameters == null || onDataParameters.length < 1) {
+ return null;
+ }
+ DartType eventType = onDataParameters[0].type;
+ if (eventType.element == streamType.typeParameters[0]) {
+ return streamType.typeArguments[0];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
* required type is [FunctionType], then infer parameters types from [FunctionType].
*/
@@ -11150,7 +11254,7 @@
// If the expectedClosureType is not more specific than the static type,
// return.
DartType staticClosureType =
- (closure.element != null ? closure.element.type : null) as DartType;
+ closure.element != null ? closure.element.type : null;
if (staticClosureType != null &&
!expectedClosureType.isMoreSpecificThan(staticClosureType)) {
return;
@@ -11540,8 +11644,11 @@
// 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.displayName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION,
+ return new AnalysisError(
+ source,
+ duplicate.nameOffset,
+ duplicate.displayName.length,
+ CompileTimeErrorCode.DUPLICATE_DEFINITION,
[existing.displayName]);
}
@@ -11640,7 +11747,7 @@
/**
* The element for the library containing the compilation unit being visited.
*/
- LibraryElement _definingLibrary;
+ final LibraryElement definingLibrary;
/**
* The source representing the compilation unit being visited.
@@ -11650,7 +11757,7 @@
/**
* The error listener that will be informed of any errors that are found during resolution.
*/
- AnalysisErrorListener _errorListener;
+ final AnalysisErrorListener errorListener;
/**
* The scope used to resolve identifiers.
@@ -11694,10 +11801,9 @@
* first be visited. If `null` or unspecified, a new [LibraryScope] will be
* created based on [definingLibrary] and [typeProvider].
*/
- ScopedVisitor(LibraryElement definingLibrary, this.source, this.typeProvider,
- AnalysisErrorListener errorListener, {Scope nameScope}) {
- this._definingLibrary = definingLibrary;
- this._errorListener = errorListener;
+ ScopedVisitor(
+ this.definingLibrary, this.source, this.typeProvider, this.errorListener,
+ {Scope nameScope}) {
if (nameScope == null) {
this.nameScope = new LibraryScope(definingLibrary, errorListener);
} else {
@@ -11706,13 +11812,6 @@
}
/**
- * Return the library element for the library containing the compilation unit being resolved.
- *
- * @return the library element for the library containing the compilation unit being resolved
- */
- LibraryElement get definingLibrary => _definingLibrary;
-
- /**
* Return the implicit label scope in which the current node is being
* resolved.
*/
@@ -11748,7 +11847,7 @@
*/
void reportErrorForNode(ErrorCode errorCode, AstNode node,
[List<Object> arguments]) {
- _errorListener.onError(new AnalysisError(
+ errorListener.onError(new AnalysisError(
source, node.offset, node.length, errorCode, arguments));
}
@@ -11762,7 +11861,7 @@
*/
void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
[List<Object> arguments]) {
- _errorListener.onError(
+ errorListener.onError(
new AnalysisError(source, offset, length, errorCode, arguments));
}
@@ -11775,7 +11874,7 @@
*/
void reportErrorForToken(ErrorCode errorCode, sc.Token token,
[List<Object> arguments]) {
- _errorListener.onError(new AnalysisError(
+ errorListener.onError(new AnalysisError(
source, token.offset, token.length, errorCode, arguments));
}
@@ -13243,13 +13342,13 @@
@override
List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
- nullType,
- numType,
- intType,
- doubleType,
- boolType,
- stringType
- ];
+ nullType,
+ numType,
+ intType,
+ doubleType,
+ boolType,
+ stringType
+ ];
@override
DartObjectImpl get nullObject {
@@ -13380,7 +13479,7 @@
TypeProvider typeProvider, AnalysisErrorListener errorListener,
{Scope nameScope})
: super(definingLibrary, source, typeProvider, errorListener,
- nameScope: nameScope) {
+ nameScope: nameScope) {
_dynamicType = typeProvider.dynamicType;
_undefinedType = typeProvider.undefinedType;
}
@@ -13776,13 +13875,15 @@
(parent.parent as InstanceCreationExpression).isConst) {
// If, if this is a const expression, then generate a
// CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
- reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE,
+ reportErrorForNode(
+ CompileTimeErrorCode.CONST_WITH_NON_TYPE,
prefixedIdentifier.identifier,
[prefixedIdentifier.identifier.name]);
} else {
// Else, if this expression is a new expression, report a
// NEW_WITH_NON_TYPE warning.
- reportErrorForNode(StaticWarningCode.NEW_WITH_NON_TYPE,
+ reportErrorForNode(
+ StaticWarningCode.NEW_WITH_NON_TYPE,
prefixedIdentifier.identifier,
[prefixedIdentifier.identifier.name]);
}
@@ -13960,11 +14061,8 @@
typeArguments[i] = argumentType;
}
} else {
- reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node, [
- typeName.name,
- parameterCount,
- argumentCount
- ]);
+ reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node,
+ [typeName.name, parameterCount, argumentCount]);
for (int i = 0; i < parameterCount; i++) {
typeArguments[i] = _dynamicType;
}
@@ -14328,7 +14426,8 @@
void _resolve(ClassElementImpl classElement, WithClause withClause,
ImplementsClause implementsClause) {
if (withClause != null) {
- List<InterfaceType> mixinTypes = _resolveTypes(withClause.mixinTypes,
+ List<InterfaceType> mixinTypes = _resolveTypes(
+ withClause.mixinTypes,
CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
CompileTimeErrorCode.MIXIN_OF_ENUM,
CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
@@ -14340,7 +14439,8 @@
}
if (implementsClause != null) {
NodeList<TypeName> interfaces = implementsClause.interfaces;
- List<InterfaceType> interfaceTypes = _resolveTypes(interfaces,
+ List<InterfaceType> interfaceTypes = _resolveTypes(
+ interfaces,
CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
CompileTimeErrorCode.IMPLEMENTS_ENUM,
CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
@@ -14415,8 +14515,10 @@
* @param dynamicTypeError the error to produce if the type name is "dynamic"
* @return an array containing all of the types that were resolved.
*/
- List<InterfaceType> _resolveTypes(NodeList<TypeName> typeNames,
- ErrorCode nonTypeError, ErrorCode enumTypeError,
+ List<InterfaceType> _resolveTypes(
+ NodeList<TypeName> typeNames,
+ ErrorCode nonTypeError,
+ ErrorCode enumTypeError,
ErrorCode dynamicTypeError) {
List<InterfaceType> types = new List<InterfaceType>();
for (TypeName typeName in typeNames) {
@@ -14648,10 +14750,8 @@
@override
visitClassElement(ClassElement element) {
if (!_isUsedElement(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
+ [element.kind.displayName, element.displayName]);
}
super.visitClassElement(element);
}
@@ -14668,10 +14768,8 @@
@override
visitFunctionElement(FunctionElement element) {
if (!_isUsedElement(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
+ [element.kind.displayName, element.displayName]);
}
super.visitFunctionElement(element);
}
@@ -14679,10 +14777,8 @@
@override
visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
if (!_isUsedElement(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
+ [element.kind.displayName, element.displayName]);
}
super.visitFunctionTypeAliasElement(element);
}
@@ -14705,10 +14801,8 @@
@override
visitMethodElement(MethodElement element) {
if (!_isUsedMember(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
+ [element.kind.displayName, element.displayName]);
}
super.visitMethodElement(element);
}
@@ -14716,10 +14810,8 @@
@override
visitPropertyAccessorElement(PropertyAccessorElement element) {
if (!_isUsedMember(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
+ [element.kind.displayName, element.displayName]);
}
super.visitPropertyAccessorElement(element);
}
@@ -14779,8 +14871,11 @@
void _reportErrorForElement(
ErrorCode errorCode, Element element, List<Object> arguments) {
if (element != null) {
- _errorListener.onError(new AnalysisError(element.source,
- element.nameOffset, element.displayName.length, errorCode,
+ _errorListener.onError(new AnalysisError(
+ element.source,
+ element.nameOffset,
+ element.displayName.length,
+ errorCode,
arguments));
}
}
@@ -14908,7 +15003,7 @@
TypeProvider typeProvider, AnalysisErrorListener errorListener,
{Scope nameScope})
: super(definingLibrary, source, typeProvider, errorListener,
- nameScope: nameScope);
+ nameScope: nameScope);
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
@@ -14923,8 +15018,8 @@
VariableResolverVisitor.con1(
Library library, Source source, TypeProvider typeProvider)
: this(
- library.libraryElement, source, typeProvider, library.errorListener,
- nameScope: library.libraryScope);
+ library.libraryElement, source, typeProvider, library.errorListener,
+ nameScope: library.libraryScope);
@override
Object visitExportDirective(ExportDirective node) => null;
@@ -15033,11 +15128,14 @@
List<ParameterElement> parameterElements;
- _ConstantVerifier_validateInitializerExpression(TypeProvider typeProvider,
- ErrorReporter errorReporter, this.verifier, this.parameterElements,
+ _ConstantVerifier_validateInitializerExpression(
+ TypeProvider typeProvider,
+ ErrorReporter errorReporter,
+ this.verifier,
+ this.parameterElements,
DeclaredVariables declaredVariables)
: super(new ConstantEvaluationEngine(typeProvider, declaredVariables),
- errorReporter);
+ errorReporter);
@override
DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index 9e028ca..0a9fa2a 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -1501,8 +1501,8 @@
}
recordStartOfLine();
} else if (next == 0xA) {
- recordStartOfLine();
next = _reader.advance();
+ recordStartOfLine();
} else {
next = _reader.advance();
}
@@ -2010,9 +2010,7 @@
/**
* Initialize a newly created token to have the given [type] and [offset].
*/
- Token(this.type, int offset) {
- this.offset = offset;
- }
+ Token(this.type, this.offset);
/**
* Return the offset from the beginning of the file to the character after the
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 81c8a88..2b4fc6e 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -303,7 +303,7 @@
* The short name of the library. This is the name used after 'dart:' in a
* URI.
*/
- String _shortName = null;
+ final String shortName;
/**
* The path to the file defining the library. The path is relative to the
@@ -337,9 +337,7 @@
* Initialize a newly created library to represent the library with the given
* [name].
*/
- SdkLibraryImpl(String name) {
- this._shortName = name;
- }
+ SdkLibraryImpl(this.shortName);
/**
* Set whether the library is documented.
@@ -373,9 +371,6 @@
@override
bool get isVmLibrary => (_platforms & VM_PLATFORM) != 0;
- @override
- String get shortName => _shortName;
-
/**
* Record that this library can be compiled to JavaScript by dart2js.
*/
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 5b96dbd..7db8cbe 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -109,7 +109,7 @@
CustomUriResolver(this._urlMappings);
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
String mapping = _urlMappings[uri.toString()];
if (mapping == null) return null;
@@ -117,7 +117,7 @@
if (!fileUri.isAbsolute) return null;
JavaFile javaFile = new JavaFile.fromUri(fileUri);
- return new FileBasedSource(javaFile);
+ return new FileBasedSource(javaFile, actualUri != null ? actualUri : uri);
}
}
@@ -156,7 +156,7 @@
DartSdk get dartSdk => _sdk;
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (!isDartUri(uri)) {
return null;
}
@@ -814,22 +814,30 @@
}
containedUri = containingSource.resolveRelativeUri(containedUri);
}
- // Now check .packages.
+
+ Uri actualUri = containedUri;
+
+ // Check .packages and update target and actual URIs as appropriate.
if (_packages != null && containedUri.scheme == 'package') {
Uri packageUri =
_packages.resolve(containedUri, notFound: (Uri packageUri) => null);
- // Ensure scheme is set.
- if (packageUri != null && packageUri.scheme == '') {
- packageUri = packageUri.replace(scheme: 'file');
+
+ if (packageUri != null) {
+ // Ensure scheme is set.
+ if (packageUri.scheme == '') {
+ packageUri = packageUri.replace(scheme: 'file');
+ }
+ containedUri = packageUri;
}
- containedUri = packageUri;
}
+
for (UriResolver resolver in _resolvers) {
- Source result = resolver.resolveAbsolute(containedUri);
+ Source result = resolver.resolveAbsolute(containedUri, actualUri);
if (result != null) {
return result;
}
}
+
return null;
}
}
@@ -1062,9 +1070,10 @@
* resolved because the URI is invalid.
*
* @param uri the URI to be resolved
+ * @param actualUri the actual uri for this source -- if `null`, the value of [uri] will be used
* @return a [Source] representing the file to which given URI was resolved
*/
- Source resolveAbsolute(Uri uri);
+ Source resolveAbsolute(Uri uri, [Uri actualUri]);
/**
* Return an absolute URI that represents the given source, or `null` if a valid URI cannot
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 9c40d74..fa32b4b 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -276,11 +276,12 @@
static String FILE_SCHEME = "file";
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (!isFileUri(uri)) {
return null;
}
- return new FileBasedSource(new JavaFile.fromUri(uri), uri);
+ return new FileBasedSource(
+ new JavaFile.fromUri(uri), actualUri != null ? actualUri : uri);
}
@override
@@ -290,7 +291,7 @@
}
return null;
}
-
+
/**
* Return `true` if the given URI is a `file` URI.
*
@@ -425,7 +426,7 @@
}
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (!isPackageUri(uri)) {
return null;
}
@@ -459,11 +460,13 @@
if (_isSelfReference(packagesDirectory, canonicalFile)) {
uri = canonicalFile.toURI();
}
- return new FileBasedSource(canonicalFile, uri);
+ return new FileBasedSource(
+ canonicalFile, actualUri != null ? actualUri : uri);
}
}
return new FileBasedSource(
- getCanonicalFile(_packagesDirectories[0], pkgName, relPath), uri);
+ getCanonicalFile(_packagesDirectories[0], pkgName, relPath),
+ actualUri != null ? actualUri : uri);
}
@override
@@ -537,7 +540,7 @@
: super();
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
String rootPath = _rootDirectory.toURI().path;
String uriPath = uri.path;
if (uriPath != null && uriPath.startsWith(rootPath)) {
@@ -545,7 +548,7 @@
for (JavaFile dir in _relativeDirectories) {
JavaFile file = new JavaFile.relative(dir, filePath);
if (file.exists()) {
- return new FileBasedSource(file, uri);
+ return new FileBasedSource(file, actualUri != null ? actualUri : uri);
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 4c2a537..d6a4c78 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -197,7 +197,8 @@
}
static ExportElementImpl exportFor(LibraryElement exportedLibrary,
- [List<NamespaceCombinator> combinators = NamespaceCombinator.EMPTY_LIST]) {
+ [List<NamespaceCombinator> combinators =
+ NamespaceCombinator.EMPTY_LIST]) {
ExportElementImpl spec = new ExportElementImpl(-1);
spec.exportedLibrary = exportedLibrary;
spec.combinators = combinators;
@@ -226,8 +227,9 @@
setter.setter = true;
setter.synthetic = true;
setter.variable = field;
- setter.parameters =
- <ParameterElement>[requiredParameter2("_$name", type)];
+ setter.parameters = <ParameterElement>[
+ requiredParameter2("_$name", type)
+ ];
setter.returnType = VoidTypeImpl.instance;
setter.type = new FunctionTypeImpl(setter);
field.setter = setter;
@@ -236,7 +238,8 @@
}
static FieldFormalParameterElementImpl fieldFormalParameter(
- Identifier name) => new FieldFormalParameterElementImpl(name);
+ Identifier name) =>
+ new FieldFormalParameterElementImpl(name);
static FunctionElementImpl functionElement(String functionName) =>
functionElement4(functionName, null, null, null, null);
@@ -245,9 +248,11 @@
String functionName, ClassElement returnElement) =>
functionElement3(functionName, returnElement, null, null);
- static FunctionElementImpl functionElement3(String functionName,
- ClassElement returnElement, List<ClassElement> normalParameters,
- List<ClassElement> optionalParameters) {
+ static FunctionElementImpl functionElement3(
+ String functionName,
+ ClassElement returnElement,
+ List<TypeDefiningElement> normalParameters,
+ List<TypeDefiningElement> optionalParameters) {
// We don't create parameter elements because we don't have parameter names
FunctionElementImpl functionElement =
new FunctionElementImpl(functionName, 0);
@@ -281,9 +286,12 @@
return functionElement;
}
- static FunctionElementImpl functionElement4(String functionName,
- ClassElement returnElement, List<ClassElement> normalParameters,
- List<String> names, List<ClassElement> namedParameters) {
+ static FunctionElementImpl functionElement4(
+ String functionName,
+ ClassElement returnElement,
+ List<ClassElement> normalParameters,
+ List<String> names,
+ List<ClassElement> namedParameters) {
FunctionElementImpl functionElement =
new FunctionElementImpl(functionName, 0);
FunctionTypeImpl functionType = new FunctionTypeImpl(functionElement);
@@ -326,14 +334,19 @@
String functionName, List<ClassElement> normalParameters) =>
functionElement3(functionName, null, normalParameters, null);
- static FunctionElementImpl functionElement6(String functionName,
- List<ClassElement> normalParameters,
- List<ClassElement> optionalParameters) => functionElement3(
+ static FunctionElementImpl functionElement6(
+ String functionName,
+ List<ClassElement> normalParameters,
+ List<ClassElement> optionalParameters) =>
+ functionElement3(
functionName, null, normalParameters, optionalParameters);
- static FunctionElementImpl functionElement7(String functionName,
- List<ClassElement> normalParameters, List<String> names,
- List<ClassElement> namedParameters) => functionElement4(
+ static FunctionElementImpl functionElement7(
+ String functionName,
+ List<ClassElement> normalParameters,
+ List<String> names,
+ List<ClassElement> namedParameters) =>
+ functionElement4(
functionName, null, normalParameters, names, namedParameters);
static FunctionElementImpl functionElementWithParameters(String functionName,
@@ -384,7 +397,8 @@
static ImportElementImpl importFor(
LibraryElement importedLibrary, PrefixElement prefix,
- [List<NamespaceCombinator> combinators = NamespaceCombinator.EMPTY_LIST]) {
+ [List<NamespaceCombinator> combinators =
+ NamespaceCombinator.EMPTY_LIST]) {
ImportElementImpl spec = new ImportElementImpl(0);
spec.importedLibrary = importedLibrary;
spec.prefix = prefix;
@@ -430,8 +444,10 @@
return method;
}
- static MethodElementImpl methodElementWithParameters(String methodName,
- List<DartType> typeArguments, DartType returnType,
+ static MethodElementImpl methodElementWithParameters(
+ String methodName,
+ List<DartType> typeArguments,
+ DartType returnType,
List<ParameterElement> parameters) {
MethodElementImpl method = new MethodElementImpl(methodName, 0);
method.parameters = parameters;
@@ -548,8 +564,9 @@
setter.static = true;
setter.synthetic = true;
setter.variable = variable;
- setter.parameters =
- <ParameterElement>[requiredParameter2("_$name", type)];
+ setter.parameters = <ParameterElement>[
+ requiredParameter2("_$name", type)
+ ];
setter.returnType = VoidTypeImpl.instance;
setter.type = new FunctionTypeImpl(setter);
variable.setter = setter;
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index fa8daec..6e3f7a4 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -3219,7 +3219,8 @@
// Use the ErrorVerifier to compute errors.
//
ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter,
- libraryElement, typeProvider, new InheritanceManager(libraryElement));
+ libraryElement, typeProvider, new InheritanceManager(libraryElement),
+ context.analysisOptions.enableSuperMixins);
unit.accept(errorVerifier);
//
// Record outputs.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 32c8bf7..77b064e 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.25.3-alpha.1
+version: 0.26.0
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index d941fcf..29e0b67 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -4,7 +4,6 @@
library engine.compile_time_error_code_test;
-import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/source_io.dart';
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index af6dac3..13c0b66 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -2263,6 +2263,7 @@
options.cacheSize = i;
options.dart2jsHint = booleanValue;
options.enableStrictCallChecks = booleanValue;
+ options.enableSuperMixins = booleanValue;
options.generateImplicitErrors = booleanValue;
options.generateSdkErrors = booleanValue;
options.hint = booleanValue;
@@ -2274,6 +2275,7 @@
expect(copy.cacheSize, options.cacheSize);
expect(copy.dart2jsHint, options.dart2jsHint);
expect(copy.enableStrictCallChecks, options.enableStrictCallChecks);
+ expect(copy.enableSuperMixins, options.enableSuperMixins);
expect(copy.generateImplicitErrors, options.generateImplicitErrors);
expect(copy.generateSdkErrors, options.generateSdkErrors);
expect(copy.hint, options.hint);
@@ -2305,11 +2307,11 @@
expect(options.dart2jsHint, value);
}
- void test_strongMode() {
+ void test_enableSuperMixins() {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
- bool value = !options.strongMode;
- options.strongMode = value;
- expect(options.strongMode, value);
+ bool value = !options.enableSuperMixins;
+ options.enableSuperMixins = value;
+ expect(options.enableSuperMixins, value);
}
void test_generateImplicitErrors() {
@@ -2346,6 +2348,13 @@
options.preserveComments = value;
expect(options.preserveComments, value);
}
+
+ void test_strongMode() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ bool value = !options.strongMode;
+ options.strongMode = value;
+ expect(options.strongMode, value);
+ }
}
class AnalysisTask_test_perform_exception extends AnalysisTask {
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index ed41b59..7af5e3ab 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -3872,6 +3872,20 @@
''');
}
+ void _assertEqualLineInfo(LineInfo incrLineInfo, LineInfo fullLineInfo) {
+ for (int offset = 0; offset < 1000; offset++) {
+ LineInfo_Location incrLocation = incrLineInfo.getLocation(offset);
+ LineInfo_Location fullLocation = fullLineInfo.getLocation(offset);
+ if (incrLocation.lineNumber != fullLocation.lineNumber ||
+ incrLocation.columnNumber != fullLocation.columnNumber) {
+ fail('At offset $offset ' +
+ '(${incrLocation.lineNumber}, ${incrLocation.columnNumber})' +
+ ' != ' +
+ '(${fullLocation.lineNumber}, ${fullLocation.columnNumber})');
+ }
+ }
+ }
+
/**
* Reset the analysis context to have the 'incremental' option set to the
* given value.
@@ -3910,6 +3924,7 @@
analysisContext2.setContents(source, newCode);
CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
List<AnalysisError> newErrors = analysisContext.computeErrors(source);
+ LineInfo newLineInfo = analysisContext.getLineInfo(source);
// check for expected failure
if (!expectedSuccess) {
expect(newUnit.element, isNot(same(oldUnitElement)));
@@ -3932,6 +3947,8 @@
CompilationUnit fullNewUnit = resolveCompilationUnit(source, library);
// Validate tokens.
_assertEqualTokens(newUnit, fullNewUnit);
+ // Validate LineInfo
+ _assertEqualLineInfo(newLineInfo, analysisContext.getLineInfo(source));
// Validate that "incremental" and "full" units have the same resolution.
try {
assertSameResolution(newUnit, fullNewUnit, validateTypes: true);
@@ -3941,7 +3958,6 @@
List<AnalysisError> newFullErrors =
analysisContext.getErrors(source).errors;
_assertEqualErrors(newErrors, newFullErrors);
- // TODO(scheglov) check line info
}
}
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index c77d424..64da228 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -3140,6 +3140,19 @@
verify([source]);
}
+ void test_mixinInheritsFromNotObject_classDeclaration_extends() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableSuperMixins = true;
+ resetWithOptions(options);
+ Source source = addSource(r'''
+class A {}
+class B extends A {}
+class C extends Object with B {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_mixinInheritsFromNotObject_classDeclaration_mixTypeAlias() {
Source source = addSource(r'''
class A {}
@@ -3150,6 +3163,45 @@
verify([source]);
}
+ void test_mixinInheritsFromNotObject_classDeclaration_with() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableSuperMixins = true;
+ resetWithOptions(options);
+ Source source = addSource(r'''
+class A {}
+class B extends Object with A {}
+class C extends Object with B {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_mixinInheritsFromNotObject_typeAlias_extends() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableSuperMixins = true;
+ resetWithOptions(options);
+ Source source = addSource(r'''
+class A {}
+class B extends A {}
+class C = Object with B;''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_mixinInheritsFromNotObject_typeAlias_with() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableSuperMixins = true;
+ resetWithOptions(options);
+ Source source = addSource(r'''
+class A {}
+class B extends Object with A {}
+class C = Object with B;''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_mixinInheritsFromNotObject_typedef_mixTypeAlias() {
Source source = addSource(r'''
class A {}
@@ -3160,6 +3212,20 @@
verify([source]);
}
+ void test_mixinReferencesSuper() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableSuperMixins = true;
+ resetWithOptions(options);
+ Source source = addSource(r'''
+class A {
+ toString() => super.toString();
+}
+class B extends Object with A {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_multipleSuperInitializers_no() {
Source source = addSource(r'''
class A {}
@@ -5002,12 +5068,14 @@
verify([source]);
}
- void test_undefinedGetter_typeLiteral_conditionalAccess() {
- // When applied to a type literal, the conditional access operator '?.' can
- // be used to access instance getters of Type.
+ void test_undefinedGetter_static_conditionalAccess() {
+ // The conditional access operator '?.' can be used to access static
+ // fields.
Source source = addSource('''
-class A {}
-f() => A?.hashCode;
+class A {
+ static var x;
+}
+var a = A?.x;
''');
computeLibrarySourceErrors(source);
assertNoErrors(source);
@@ -5089,12 +5157,14 @@
// A call to verify(source) fails as '(() => null)()' isn't resolved.
}
- void test_undefinedMethod_typeLiteral_conditionalAccess() {
- // When applied to a type literal, the conditional access operator '?.' can
- // be used to access instance methods of Type.
+ void test_undefinedMethod_static_conditionalAccess() {
+ // The conditional access operator '?.' can be used to access static
+ // methods.
Source source = addSource('''
-class A {}
-f() => A?.toString();
+class A {
+ static void m() {}
+}
+f() { A?.m(); }
''');
computeLibrarySourceErrors(source);
assertNoErrors(source);
@@ -5139,6 +5209,20 @@
verify([source]);
}
+ void test_undefinedSetter_static_conditionalAccess() {
+ // The conditional access operator '?.' can be used to access static
+ // fields.
+ Source source = addSource('''
+class A {
+ static var x;
+}
+f() { A?.x = 1; }
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_undefinedSuperMethod_field() {
Source source = addSource(r'''
class A {
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 89242b9..4034068 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -165,7 +165,8 @@
ElementFactory.topLevelVariableElement3(
"deprecated", true, false, provider.deprecatedType);
deprecatedTopLevelVariableElt.constantInitializer = AstFactory
- .instanceCreationExpression2(Keyword.CONST,
+ .instanceCreationExpression2(
+ Keyword.CONST,
AstFactory.typeName(provider.deprecatedType.element),
[AstFactory.string2('next release')]);
coreUnit.accessors = <PropertyAccessorElement>[
@@ -229,10 +230,29 @@
(completerConstructor.type as FunctionTypeImpl).typeArguments =
completerElement.type.typeArguments;
completerElement.constructors = <ConstructorElement>[completerConstructor];
+ // StreamSubscription
+ ClassElementImpl streamSubscriptionElement =
+ ElementFactory.classElement2("StreamSubscription", ["T"]);
+ // Stream
+ ClassElementImpl streamElement =
+ ElementFactory.classElement2("Stream", ["T"]);
+ DartType returnType = streamSubscriptionElement.type
+ .substitute4(streamElement.type.typeArguments);
+ List<DartType> parameterTypes = <DartType>[
+ ElementFactory
+ .functionElement3('onData', VoidTypeImpl.instance.element,
+ <TypeDefiningElement>[streamElement.typeParameters[0]], null)
+ .type,
+ ];
+ // TODO(brianwilkerson) This is missing the optional parameters.
+ MethodElementImpl listenMethod =
+ ElementFactory.methodElement('listen', returnType, parameterTypes);
+ streamElement.methods = <MethodElement>[listenMethod];
+
asyncUnit.types = <ClassElement>[
completerElement,
futureElement,
- ElementFactory.classElement2("Stream", ["T"])
+ streamElement
];
LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
coreContext, AstFactory.libraryIdentifier2(["dart", "async"]));
@@ -306,8 +326,10 @@
Source mathSource = sourceFactory.forUri(_DART_MATH);
coreContext.setContents(mathSource, "");
mathUnit.librarySource = mathUnit.source = mathSource;
- FunctionElement cosElement = ElementFactory.functionElement3("cos",
- provider.doubleType.element, <ClassElement>[provider.numType.element],
+ FunctionElement cosElement = ElementFactory.functionElement3(
+ "cos",
+ provider.doubleType.element,
+ <ClassElement>[provider.numType.element],
ClassElement.EMPTY_LIST);
TopLevelVariableElement ln10Element = ElementFactory
.topLevelVariableElement3("LN10", true, false, provider.doubleType);
@@ -323,11 +345,15 @@
seedParam.type = provider.intType;
randomConstructor.parameters = <ParameterElement>[seedParam];
randomElement.constructors = <ConstructorElement>[randomConstructor];
- FunctionElement sinElement = ElementFactory.functionElement3("sin",
- provider.doubleType.element, <ClassElement>[provider.numType.element],
+ FunctionElement sinElement = ElementFactory.functionElement3(
+ "sin",
+ provider.doubleType.element,
+ <ClassElement>[provider.numType.element],
ClassElement.EMPTY_LIST);
- FunctionElement sqrtElement = ElementFactory.functionElement3("sqrt",
- provider.doubleType.element, <ClassElement>[provider.numType.element],
+ FunctionElement sqrtElement = ElementFactory.functionElement3(
+ "sqrt",
+ provider.doubleType.element,
+ <ClassElement>[provider.numType.element],
ClassElement.EMPTY_LIST);
mathUnit.accessors = <PropertyAccessorElement>[
ln10Element.getter,
@@ -1208,8 +1234,9 @@
fail("Not yet tested");
// Need to set up the exported library so that the identifier can be
// resolved.
- ExportDirective directive =
- AstFactory.exportDirective2(null, [AstFactory.hideCombinator2(["A"])]);
+ ExportDirective directive = AstFactory.exportDirective2(null, [
+ AstFactory.hideCombinator2(["A"])
+ ]);
_resolveNode(directive);
_listener.assertNoErrors();
}
@@ -1223,8 +1250,9 @@
fail("Not yet tested");
// Need to set up the imported library so that the identifier can be
// resolved.
- ImportDirective directive = AstFactory.importDirective3(
- null, null, [AstFactory.showCombinator2(["A"])]);
+ ImportDirective directive = AstFactory.importDirective3(null, null, [
+ AstFactory.showCombinator2(["A"])
+ ]);
_resolveNode(directive);
_listener.assertNoErrors();
}
@@ -1324,8 +1352,10 @@
_resolveNode(expression);
var stringElement = stringType.element;
expect(expression.staticElement, isNotNull);
- expect(expression.staticElement, stringElement.lookUpMethod(
- TokenType.EQ_EQ.lexeme, stringElement.library));
+ expect(
+ expression.staticElement,
+ stringElement.lookUpMethod(
+ TokenType.EQ_EQ.lexeme, stringElement.library));
expect(expression.propagatedElement, isNull);
_listener.assertNoErrors();
}
@@ -1341,8 +1371,10 @@
left, TokenType.EQ_EQ, AstFactory.identifier3("j"));
_resolveNode(expression);
var stringElement = stringType.element;
- expect(expression.staticElement, stringElement.lookUpMethod(
- TokenType.EQ_EQ.lexeme, stringElement.library));
+ expect(
+ expression.staticElement,
+ stringElement.lookUpMethod(
+ TokenType.EQ_EQ.lexeme, stringElement.library));
expect(expression.propagatedElement, isNull);
_listener.assertNoErrors();
}
@@ -1613,12 +1645,17 @@
AstFactory.typeName(classA), constructorName);
name.staticElement = constructor;
InstanceCreationExpression creation = AstFactory.instanceCreationExpression(
- Keyword.NEW, name,
+ Keyword.NEW,
+ name,
[AstFactory.namedExpression2(parameterName, AstFactory.integer(0))]);
_resolveNode(creation);
expect(creation.staticElement, same(constructor));
- expect((creation.argumentList.arguments[
- 0] as NamedExpression).name.label.staticElement, same(parameter));
+ expect(
+ (creation.argumentList.arguments[0] as NamedExpression)
+ .name
+ .label
+ .staticElement,
+ same(parameter));
_listener.assertNoErrors();
}
@@ -1648,8 +1685,12 @@
[AstFactory.namedExpression2(parameterName, AstFactory.integer(0))]);
_resolveNode(invocation);
expect(invocation.methodName.staticElement, same(method));
- expect((invocation.argumentList.arguments[
- 0] as NamedExpression).name.label.staticElement, same(parameter));
+ expect(
+ (invocation.argumentList.arguments[0] as NamedExpression)
+ .name
+ .label
+ .staticElement,
+ same(parameter));
_listener.assertNoErrors();
}
@@ -1808,8 +1849,13 @@
SuperExpression target = AstFactory.superExpression();
target.staticType = ElementFactory.classElement("B", classA.type).type;
PropertyAccess access = AstFactory.propertyAccess2(target, getterName);
- AstFactory.methodDeclaration2(null, null, null, null,
- AstFactory.identifier3("m"), AstFactory.formalParameterList(),
+ AstFactory.methodDeclaration2(
+ null,
+ null,
+ null,
+ null,
+ AstFactory.identifier3("m"),
+ AstFactory.formalParameterList(),
AstFactory.expressionFunctionBody(access));
_resolveNode(access);
expect(access.propertyName.staticElement, same(getter));
@@ -1910,8 +1956,12 @@
]);
_resolveInClass(invocation, subclass);
expect(invocation.staticElement, superConstructor);
- expect((invocation.argumentList.arguments[
- 0] as NamedExpression).name.label.staticElement, same(parameter));
+ expect(
+ (invocation.argumentList.arguments[0] as NamedExpression)
+ .name
+ .label
+ .staticElement,
+ same(parameter));
_listener.assertNoErrors();
}
@@ -2241,10 +2291,14 @@
import 'lib1.dart' as one;
import 'lib2.dart' as one;
one.A a;''');
- Source source2 = addNamedSource("/lib1.dart", r'''
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
- Source source3 = addNamedSource("/lib2.dart", r'''
+ Source source3 = addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
class B {}''');
computeLibrarySourceErrors(source);
@@ -2717,7 +2771,9 @@
void test_deprecatedAnnotationUse_export() {
Source source = addSource("export 'deprecated_library.dart';");
- addNamedSource("/deprecated_library.dart", r'''
+ addNamedSource(
+ "/deprecated_library.dart",
+ r'''
@deprecated
library deprecated_library;
class A {}''');
@@ -2744,7 +2800,9 @@
Source source = addSource(r'''
import 'deprecated_library.dart';
f(A a) {}''');
- addNamedSource("/deprecated_library.dart", r'''
+ addNamedSource(
+ "/deprecated_library.dart",
+ r'''
@deprecated
library deprecated_library;
class A {}''');
@@ -2901,7 +2959,9 @@
import 'lib1.dart';
import 'lib1.dart';
A a;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
computeLibrarySourceErrors(source);
@@ -2916,7 +2976,9 @@
import 'lib1.dart';
import 'lib1.dart';
A a;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
computeLibrarySourceErrors(source);
@@ -2931,7 +2993,9 @@
import 'lib1.dart' as M show A hide B;
import 'lib1.dart' as M show A hide B;
M.A a;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}''');
@@ -2950,7 +3014,9 @@
library root;
import 'lib1.dart' deferred as lib1;
main() { lib1.f(); }'''
- ], <ErrorCode>[HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]);
+ ], <ErrorCode>[
+ HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION
+ ]);
}
void test_invalidAssignment_instanceVariable() {
@@ -4221,7 +4287,9 @@
import 'lib1.dart';
import 'lib1.dart' as one;
one.A a;''');
- Source source2 = addNamedSource("/lib1.dart", r'''
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
computeLibrarySourceErrors(source);
@@ -4236,7 +4304,9 @@
import 'lib1.dart';
import 'lib1.dart' hide A;
A a;''');
- Source source2 = addNamedSource("/lib1.dart", r'''
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
computeLibrarySourceErrors(source);
@@ -4251,7 +4321,9 @@
import 'lib1.dart' show A;
import 'lib1.dart' show B;
A a;''');
- Source source2 = addNamedSource("/lib1.dart", r'''
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}''');
@@ -5787,14 +5859,20 @@
}
void test_accessorsAcrossFiles() {
- Source librarySource = addSource("/lib.dart", r'''
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
library lib;
part 'first.dart';
part 'second.dart';''');
- addSource("/first.dart", r'''
+ addSource(
+ "/first.dart",
+ r'''
part of lib;
int get V => 0;''');
- addSource("/second.dart", r'''
+ addSource(
+ "/second.dart",
+ r'''
part of lib;
void set V(int v) {}''');
LibraryElement element = _buildLibrary(librarySource);
@@ -5840,7 +5918,9 @@
void test_missingPartOfDirective() {
addSource("/a.dart", "class A {}");
- Source librarySource = addSource("/lib.dart", r'''
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
library lib;
part 'a.dart';''');
@@ -5850,16 +5930,22 @@
}
void test_multipleFiles() {
- Source librarySource = addSource("/lib.dart", r'''
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
library lib;
part 'first.dart';
part 'second.dart';
class A {}''');
- addSource("/first.dart", r'''
+ addSource(
+ "/first.dart",
+ r'''
part of lib;
class B {}''');
- addSource("/second.dart", r'''
+ addSource(
+ "/second.dart",
+ r'''
part of lib;
class C {}''');
LibraryElement element = _buildLibrary(librarySource);
@@ -5877,7 +5963,9 @@
}
void test_singleFile() {
- Source librarySource = addSource("/lib.dart", r'''
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
library lib;
class A {}''');
@@ -5946,13 +6034,13 @@
ClassElement typeB2 = ElementFactory.classElement2(typeNameB);
ClassElement typeC = ElementFactory.classElement2(typeNameC);
LibraryElement importedLibrary1 = createTestLibrary(context, "imported1");
- (importedLibrary1.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[typeA, typeB1];
+ (importedLibrary1.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[typeA, typeB1];
ImportElementImpl import1 =
ElementFactory.importFor(importedLibrary1, null);
LibraryElement importedLibrary2 = createTestLibrary(context, "imported2");
- (importedLibrary2.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[typeB2, typeC];
+ (importedLibrary2.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[typeB2, typeC];
ImportElementImpl import2 =
ElementFactory.importFor(importedLibrary2, null);
LibraryElementImpl importingLibrary =
@@ -6008,8 +6096,8 @@
ClassElement importedType =
new ClassElementImpl.forNode(AstFactory.identifier3(importedTypeName));
LibraryElement importedLibrary = createTestLibrary(context, "imported");
- (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[importedType];
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[importedType];
LibraryElementImpl definingLibrary =
createTestLibrary(context, "importing");
ImportElementImpl importElement = new ImportElementImpl(0);
@@ -6035,8 +6123,8 @@
String typeName = "List";
ClassElement type = ElementFactory.classElement2(typeName);
LibraryElement importedLibrary = createTestLibrary(context, "lib");
- (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[type];
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[type];
ImportElementImpl importCore = ElementFactory.importFor(
context.getLibraryElement(context.sourceFactory.forUri("dart:core")),
null);
@@ -6060,8 +6148,8 @@
ClassElement typeA = ElementFactory.classElement2(typeNameA);
ClassElement typeB = ElementFactory.classElement2(typeNameB);
LibraryElement importedLibrary = createTestLibrary(context, "imported");
- (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[typeA, typeB];
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[typeA, typeB];
ImportElementImpl import1 = ElementFactory.importFor(importedLibrary, null);
ImportElementImpl import2 = ElementFactory.importFor(importedLibrary, null);
LibraryElementImpl importingLibrary =
@@ -6085,14 +6173,14 @@
ClassElement nonPrefixedType = ElementFactory.classElement2(typeName);
LibraryElement prefixedLibrary =
createTestLibrary(context, "import.prefixed");
- (prefixedLibrary.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[prefixedType];
+ (prefixedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[prefixedType];
ImportElementImpl prefixedImport = ElementFactory.importFor(
prefixedLibrary, ElementFactory.prefix(prefixName));
LibraryElement nonPrefixedLibrary =
createTestLibrary(context, "import.nonPrefixed");
- (nonPrefixedLibrary.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[nonPrefixedType];
+ (nonPrefixedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[nonPrefixedType];
ImportElementImpl nonPrefixedImport =
ElementFactory.importFor(nonPrefixedLibrary, null);
LibraryElementImpl importingLibrary =
@@ -6137,7 +6225,9 @@
library libA;
import 'libB.dart';
class A {}''');
- Source sourceB = addNamedSource("/libB.dart", r'''
+ Source sourceB = addNamedSource(
+ "/libB.dart",
+ r'''
library libB;
import 'test.dart
class B {}''');
@@ -6224,8 +6314,8 @@
ClassElement importedType =
new ClassElementImpl.forNode(AstFactory.identifier3(importedTypeName));
LibraryElement importedLibrary = createTestLibrary(context, "imported");
- (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl).types =
- <ClassElement>[importedType];
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[importedType];
LibraryElementImpl definingLibrary =
createTestLibrary(context, "importing");
ImportElementImpl importElement = new ImportElementImpl(0);
@@ -6346,7 +6436,9 @@
}
Library _createLibrary(String definingCompilationUnitPath) => new Library(
- _analysisContext, _errorListener, new FileBasedSource(
+ _analysisContext,
+ _errorListener,
+ new FileBasedSource(
FileUtilities2.createFile(definingCompilationUnitPath)));
}
@@ -6506,7 +6598,9 @@
f() {
if(A.DEBUG) {}
}''');
- addNamedSource("/lib2.dart", r'''
+ addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
class A {
static const bool DEBUG = false;
@@ -6523,7 +6617,9 @@
f() {
if(LIB.A.DEBUG) {}
}''');
- addNamedSource("/lib2.dart", r'''
+ addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
class A {
static const bool DEBUG = false;
@@ -6629,7 +6725,9 @@
import 'lib1.dart' as one;
A a;
one.A a2;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
computeLibrarySourceErrors(source);
@@ -6644,7 +6742,9 @@
import 'lib1.dart' hide A;
A a;
B b;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}''');
@@ -6660,7 +6760,9 @@
import 'lib1.dart' show A;
A a;
B b;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}
class B {}''');
@@ -7208,7 +7310,9 @@
library L;
@A()
import 'lib1.dart';''');
- Source source2 = addNamedSource("/lib1.dart", r'''
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {
const A() {}
@@ -7226,10 +7330,14 @@
import 'lib2.dart' as one;
one.A a;
one.B b;''');
- Source source2 = addNamedSource("/lib1.dart", r'''
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class A {}''');
- Source source3 = addNamedSource("/lib2.dart", r'''
+ Source source3 = addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
class B {}''');
computeLibrarySourceErrors(source);
@@ -7253,11 +7361,15 @@
library L;
import 'lib1.dart';
Two two;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
export 'lib2.dart';
class One {}''');
- addNamedSource("/lib2.dart", r'''
+ addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
class Two {}''');
computeLibrarySourceErrors(source);
@@ -7270,15 +7382,21 @@
library L;
import 'lib1.dart';
Three three;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
export 'lib2.dart';
class One {}''');
- addNamedSource("/lib2.dart", r'''
+ addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
export 'lib3.dart';
class Two {}''');
- addNamedSource("/lib3.dart", r'''
+ addNamedSource(
+ "/lib3.dart",
+ r'''
library lib3;
class Three {}''');
computeLibrarySourceErrors(source);
@@ -7291,15 +7409,21 @@
library L;
import 'lib1.dart';
Two two;''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
export 'lib2.dart';
class One {}''');
- addNamedSource("/lib2.dart", r'''
+ addNamedSource(
+ "/lib2.dart",
+ r'''
library lib2;
export 'lib3.dart';
class Two {}''');
- addNamedSource("/lib3.dart", r'''
+ addNamedSource(
+ "/lib3.dart",
+ r'''
library lib3;
export 'lib2.dart';
class Three {}''');
@@ -7317,7 +7441,9 @@
final int value;
const A(this.value);
}''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
const x = 0;''');
computeLibrarySourceErrors(source);
@@ -7336,7 +7462,9 @@
one.topLevelFunction();
}
}''');
- addNamedSource("/lib1.dart", r'''
+ addNamedSource(
+ "/lib1.dart",
+ r'''
library lib1;
class One {}
topLevelFunction() {}''');
@@ -7860,7 +7988,8 @@
* @return the library element that was created
*/
LibraryElementImpl createTestLibrary(
- AnalysisContext context, String libraryName, [List<String> typeNames]) {
+ AnalysisContext context, String libraryName,
+ [List<String> typeNames]) {
String fileName = "$libraryName.dart";
FileBasedSource definingCompilationUnitSource =
_createNamedSource(fileName);
@@ -7976,7 +8105,8 @@
return null;
}
- void resolveWithAndWithoutExperimental(List<String> strSources,
+ void resolveWithAndWithoutExperimental(
+ List<String> strSources,
List<ErrorCode> codesWithoutExperimental,
List<ErrorCode> codesWithExperimental) {
// Setup analysis context as non-experimental
@@ -8052,7 +8182,8 @@
@override
Element internalLookup(Identifier identifier, String name,
- LibraryElement referencingLibrary) => null;
+ LibraryElement referencingLibrary) =>
+ null;
}
class Scope_EnclosedScopeTest_test_define_normal extends Scope {
@@ -8065,7 +8196,8 @@
@override
Element internalLookup(Identifier identifier, String name,
- LibraryElement referencingLibrary) => null;
+ LibraryElement referencingLibrary) =>
+ null;
}
@reflectiveTest
@@ -8161,7 +8293,8 @@
expect(
propertyAccess.propertyName.staticElement.enclosingElement.name, 'M2');
expect(
- propertyAccess.propertyName.auxiliaryElements.staticElement.enclosingElement.name,
+ propertyAccess
+ .propertyName.auxiliaryElements.staticElement.enclosingElement.name,
'M2');
}
@@ -8736,10 +8869,14 @@
}
void test_entryPoint_exported() {
- addNamedSource("/two.dart", r'''
+ addNamedSource(
+ "/two.dart",
+ r'''
library two;
main() {}''');
- Source source = addNamedSource("/one.dart", r'''
+ Source source = addNamedSource(
+ "/one.dart",
+ r'''
library one;
export 'two.dart';''');
LibraryElement library = resolve2(source);
@@ -8752,7 +8889,9 @@
}
void test_entryPoint_local() {
- Source source = addNamedSource("/one.dart", r'''
+ Source source = addNamedSource(
+ "/one.dart",
+ r'''
library one;
main() {}''');
LibraryElement library = resolve2(source);
@@ -8774,7 +8913,9 @@
}
void test_enum_externalLibrary() {
- addNamedSource("/my_lib.dart", r'''
+ addNamedSource(
+ "/my_lib.dart",
+ r'''
library my_lib;
enum EEE {A, B, C}''');
Source source = addSource(r'''
@@ -8972,14 +9113,20 @@
}
void test_import_hide() {
- addNamedSource("lib1.dart", r'''
+ addNamedSource(
+ "lib1.dart",
+ r'''
library lib1;
set foo(value) {}
class A {}''');
- addNamedSource("lib2.dart", r'''
+ addNamedSource(
+ "lib2.dart",
+ r'''
library lib2;
set foo(value) {}''');
- Source source = addNamedSource("lib3.dart", r'''
+ Source source = addNamedSource(
+ "lib3.dart",
+ r'''
import 'lib1.dart' hide foo;
import 'lib2.dart';
@@ -8993,12 +9140,16 @@
}
void test_import_prefix() {
- addNamedSource("/two.dart", r'''
+ addNamedSource(
+ "/two.dart",
+ r'''
library two;
f(int x) {
return x * x;
}''');
- Source source = addNamedSource("/one.dart", r'''
+ Source source = addNamedSource(
+ "/one.dart",
+ r'''
library one;
import 'two.dart' as _two;
main() {
@@ -9010,10 +9161,14 @@
}
void test_import_spaceInUri() {
- addNamedSource("sub folder/lib.dart", r'''
+ addNamedSource(
+ "sub folder/lib.dart",
+ r'''
library lib;
foo() {}''');
- Source source = addNamedSource("app.dart", r'''
+ Source source = addNamedSource(
+ "app.dart",
+ r'''
import 'sub folder/lib.dart';
main() {
@@ -9205,9 +9360,9 @@
CompilationUnit unit = resolveCompilationUnit(source, library);
NodeList<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(2));
- Element expectedElement = (declarations[
- 0] as TopLevelVariableDeclaration).variables.variables[
- 0].name.staticElement;
+ Element expectedElement = (declarations[0] as TopLevelVariableDeclaration)
+ .variables
+ .variables[0].name.staticElement;
EngineTestCase.assertInstanceOf((obj) => obj is PropertyInducingElement,
PropertyInducingElement, expectedElement);
expectedElement = (expectedElement as PropertyInducingElement).getter;
@@ -9396,9 +9551,9 @@
CompilationUnit unit = resolveCompilationUnit(source, library);
NodeList<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(2));
- Element expectedElement = (declarations[
- 0] as TopLevelVariableDeclaration).variables.variables[
- 0].name.staticElement;
+ Element expectedElement = (declarations[0] as TopLevelVariableDeclaration)
+ .variables
+ .variables[0].name.staticElement;
EngineTestCase.assertInstanceOf((obj) => obj is PropertyInducingElement,
PropertyInducingElement, expectedElement);
expectedElement = (expectedElement as PropertyInducingElement).getter;
@@ -9919,11 +10074,15 @@
// class A extends Derived<int> implements Derived<num> { ... }
ClassElementImpl classA =
ElementFactory.classElement('A', derivedType.substitute4([intType]));
- classA.interfaces = <InterfaceType>[derivedType.substitute4([numType])];
+ classA.interfaces = <InterfaceType>[
+ derivedType.substitute4([numType])
+ ];
// class B extends Future<num> implements Future<int> { ... }
ClassElementImpl classB =
ElementFactory.classElement('B', derivedType.substitute4([numType]));
- classB.interfaces = <InterfaceType>[derivedType.substitute4([intType])];
+ classB.interfaces = <InterfaceType>[
+ derivedType.substitute4([intType])
+ ];
// flatten(A) = flatten(B) = int, since int is more specific than num.
// The code in flatten() that inhibits infinite recursion shouldn't be
// fooled by the fact that Derived appears twice in the type hierarchy.
@@ -9938,11 +10097,15 @@
// class A extends Future<int> implements Future<num> { ... }
ClassElementImpl classA =
ElementFactory.classElement('A', futureType.substitute4([intType]));
- classA.interfaces = <InterfaceType>[futureType.substitute4([numType])];
+ classA.interfaces = <InterfaceType>[
+ futureType.substitute4([numType])
+ ];
// class B extends Future<num> implements Future<int> { ... }
ClassElementImpl classB =
ElementFactory.classElement('B', futureType.substitute4([numType]));
- classB.interfaces = <InterfaceType>[futureType.substitute4([intType])];
+ classB.interfaces = <InterfaceType>[
+ futureType.substitute4([intType])
+ ];
// flatten(A) = flatten(B) = int, since int is more specific than num.
expect(_flatten(classA.type), intType);
expect(_flatten(classB.type), intType);
@@ -9979,11 +10142,15 @@
// class A extends Future<int> implements Future<String> { ... }
ClassElementImpl classA =
ElementFactory.classElement('A', futureType.substitute4([intType]));
- classA.interfaces = <InterfaceType>[futureType.substitute4([stringType])];
+ classA.interfaces = <InterfaceType>[
+ futureType.substitute4([stringType])
+ ];
// class B extends Future<String> implements Future<int> { ... }
ClassElementImpl classB =
ElementFactory.classElement('B', futureType.substitute4([stringType]));
- classB.interfaces = <InterfaceType>[futureType.substitute4([intType])];
+ classB.interfaces = <InterfaceType>[
+ futureType.substitute4([intType])
+ ];
// flatten(A) = A and flatten(B) = B, since neither string nor int is more
// specific than the other.
expect(_flatten(classA.type), classA.type);
@@ -10026,7 +10193,8 @@
// double d; d ??= 0
Expression node = AstFactory.assignmentExpression(
_resolvedVariable(_typeProvider.doubleType, 'd'),
- TokenType.QUESTION_QUESTION_EQ, _resolvedInteger(0));
+ TokenType.QUESTION_QUESTION_EQ,
+ _resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.numType));
_listener.assertNoErrors();
}
@@ -10035,7 +10203,8 @@
// int i; i ??= 0
Expression node = AstFactory.assignmentExpression(
_resolvedVariable(_typeProvider.intType, 'i'),
- TokenType.QUESTION_QUESTION_EQ, _resolvedInteger(0));
+ TokenType.QUESTION_QUESTION_EQ,
+ _resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
@@ -10092,7 +10261,8 @@
void test_visitBinaryExpression_logicalAnd() {
// false && true
Expression node = AstFactory.binaryExpression(
- AstFactory.booleanLiteral(false), TokenType.AMPERSAND_AMPERSAND,
+ AstFactory.booleanLiteral(false),
+ TokenType.AMPERSAND_AMPERSAND,
AstFactory.booleanLiteral(true));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
@@ -10101,7 +10271,8 @@
void test_visitBinaryExpression_logicalOr() {
// false || true
Expression node = AstFactory.binaryExpression(
- AstFactory.booleanLiteral(false), TokenType.BAR_BAR,
+ AstFactory.booleanLiteral(false),
+ TokenType.BAR_BAR,
AstFactory.booleanLiteral(true));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
@@ -10110,7 +10281,8 @@
void test_visitBinaryExpression_minusID_propagated() {
// a - b
BinaryExpression node = AstFactory.binaryExpression(
- _propagatedVariable(_typeProvider.intType, 'a'), TokenType.MINUS,
+ _propagatedVariable(_typeProvider.intType, 'a'),
+ TokenType.MINUS,
_propagatedVariable(_typeProvider.doubleType, 'b'));
node.propagatedElement = getMethod(_typeProvider.numType, "+");
_analyze(node);
@@ -10147,7 +10319,8 @@
void test_visitBinaryExpression_plusII_propagated() {
// a + b
BinaryExpression node = AstFactory.binaryExpression(
- _propagatedVariable(_typeProvider.intType, 'a'), TokenType.PLUS,
+ _propagatedVariable(_typeProvider.intType, 'a'),
+ TokenType.PLUS,
_propagatedVariable(_typeProvider.intType, 'b'));
node.propagatedElement = getMethod(_typeProvider.numType, "+");
_analyze(node);
@@ -10174,9 +10347,11 @@
MethodElement operator =
ElementFactory.methodElement("*", typeA, [_typeProvider.doubleType]);
classA.methods = <MethodElement>[operator];
- BinaryExpression node = AstFactory.binaryExpression(AstFactory.asExpression(
+ BinaryExpression node = AstFactory.binaryExpression(
+ AstFactory.asExpression(
AstFactory.identifier3("a"), AstFactory.typeName(classA)),
- TokenType.PLUS, _resolvedDouble(2.0));
+ TokenType.PLUS,
+ _resolvedDouble(2.0));
node.staticElement = operator;
expect(_analyze(node), same(typeA));
_listener.assertNoErrors();
@@ -10216,7 +10391,8 @@
void test_visitConditionalExpression_differentTypes() {
// true ? 1.0 : 0
Expression node = AstFactory.conditionalExpression(
- AstFactory.booleanLiteral(true), _resolvedDouble(1.0),
+ AstFactory.booleanLiteral(true),
+ _resolvedDouble(1.0),
_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.numType));
_listener.assertNoErrors();
@@ -10225,7 +10401,8 @@
void test_visitConditionalExpression_sameTypes() {
// true ? 1 : 0
Expression node = AstFactory.conditionalExpression(
- AstFactory.booleanLiteral(true), _resolvedInteger(1),
+ AstFactory.booleanLiteral(true),
+ _resolvedInteger(1),
_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
@@ -10377,10 +10554,8 @@
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
- _assertFunctionType(dynamicType, <DartType>[
- dynamicType,
- dynamicType
- ], null, null, resultType);
+ _assertFunctionType(dynamicType, <DartType>[dynamicType, dynamicType], null,
+ null, resultType);
_listener.assertNoErrors();
}
@@ -10492,10 +10667,8 @@
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
- _assertFunctionType(dynamicType, null, <DartType>[
- dynamicType,
- dynamicType
- ], null, resultType);
+ _assertFunctionType(dynamicType, null, <DartType>[dynamicType, dynamicType],
+ null, resultType);
_listener.assertNoErrors();
}
@@ -10598,7 +10771,8 @@
constructor.type = constructorType;
classElement.constructors = <ConstructorElement>[constructor];
InstanceCreationExpression node = AstFactory.instanceCreationExpression2(
- null, AstFactory.typeName(classElement),
+ null,
+ AstFactory.typeName(classElement),
[AstFactory.identifier3(constructorName)]);
node.staticElement = constructor;
expect(_analyze(node), same(classElement.type));
@@ -10671,8 +10845,10 @@
// []
Expression node = AstFactory.listLiteral();
DartType resultType = _analyze(node);
- _assertType2(_typeProvider.listType
- .substitute4(<DartType>[_typeProvider.dynamicType]), resultType);
+ _assertType2(
+ _typeProvider.listType
+ .substitute4(<DartType>[_typeProvider.dynamicType]),
+ resultType);
_listener.assertNoErrors();
}
@@ -10680,8 +10856,10 @@
// [0]
Expression node = AstFactory.listLiteral([_resolvedInteger(0)]);
DartType resultType = _analyze(node);
- _assertType2(_typeProvider.listType
- .substitute4(<DartType>[_typeProvider.dynamicType]), resultType);
+ _assertType2(
+ _typeProvider.listType
+ .substitute4(<DartType>[_typeProvider.dynamicType]),
+ resultType);
_listener.assertNoErrors();
}
@@ -10689,7 +10867,8 @@
// {}
Expression node = AstFactory.mapLiteral2();
DartType resultType = _analyze(node);
- _assertType2(_typeProvider.mapType.substitute4(
+ _assertType2(
+ _typeProvider.mapType.substitute4(
<DartType>[_typeProvider.dynamicType, _typeProvider.dynamicType]),
resultType);
_listener.assertNoErrors();
@@ -10700,7 +10879,8 @@
Expression node = AstFactory
.mapLiteral2([AstFactory.mapLiteralEntry("k", _resolvedInteger(0))]);
DartType resultType = _analyze(node);
- _assertType2(_typeProvider.mapType.substitute4(
+ _assertType2(
+ _typeProvider.mapType.substitute4(
<DartType>[_typeProvider.dynamicType, _typeProvider.dynamicType]),
resultType);
_listener.assertNoErrors();
@@ -10926,8 +11106,9 @@
void test_visitThisExpression() {
// this
- InterfaceType thisType = ElementFactory.classElement(
- "B", ElementFactory.classElement2("A").type).type;
+ InterfaceType thisType = ElementFactory
+ .classElement("B", ElementFactory.classElement2("A").type)
+ .type;
Expression node = AstFactory.thisExpression();
expect(_analyze3(node, thisType), same(thisType));
_listener.assertNoErrors();
@@ -11026,9 +11207,12 @@
* @param expectedNamedTypes the expected types of the named parameters
* @param actualType the type being tested
*/
- void _assertFunctionType(DartType expectedReturnType,
- List<DartType> expectedNormalTypes, List<DartType> expectedOptionalTypes,
- Map<String, DartType> expectedNamedTypes, DartType actualType) {
+ void _assertFunctionType(
+ DartType expectedReturnType,
+ List<DartType> expectedNormalTypes,
+ List<DartType> expectedOptionalTypes,
+ Map<String, DartType> expectedNamedTypes,
+ DartType actualType) {
EngineTestCase.assertInstanceOf(
(obj) => obj is FunctionType, FunctionType, actualType);
FunctionType functionType = actualType as FunctionType;
@@ -11781,7 +11965,9 @@
@reflectiveTest
class TypePropagationTest extends ResolverTestCase {
void fail_finalPropertyInducingVariable_classMember_instance() {
- addNamedSource("/lib.dart", r'''
+ addNamedSource(
+ "/lib.dart",
+ r'''
class A {
final v = 0;
}''');
@@ -11795,7 +11981,9 @@
}
void fail_finalPropertyInducingVariable_classMember_instance_inherited() {
- addNamedSource("/lib.dart", r'''
+ addNamedSource(
+ "/lib.dart",
+ r'''
class A {
final v = 0;
}''');
@@ -11811,7 +11999,9 @@
}
void fail_finalPropertyInducingVariable_classMember_instance_propagatedTarget() {
- addNamedSource("/lib.dart", r'''
+ addNamedSource(
+ "/lib.dart",
+ r'''
class A {
final v = 0;
}''');
@@ -11827,7 +12017,9 @@
}
void fail_finalPropertyInducingVariable_classMember_static() {
- addNamedSource("/lib.dart", r'''
+ addNamedSource(
+ "/lib.dart",
+ r'''
class A {
static final V = 0;
}''');
@@ -11864,7 +12056,8 @@
void fail_mergePropagatedTypesAtJoinPoint_1() {
// https://code.google.com/p/dart/issues/detail?id=19929
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f1(x) {
var y = [];
if (x) {
@@ -11875,12 +12068,15 @@
// Propagated type is [List] here: incorrect.
// Best we can do is [Object]?
return y; // marker
-}''', null, typeProvider.dynamicType);
+}''',
+ null,
+ typeProvider.dynamicType);
}
void fail_mergePropagatedTypesAtJoinPoint_2() {
// https://code.google.com/p/dart/issues/detail?id=19929
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f2(x) {
var y = [];
if (x) {
@@ -11890,12 +12086,15 @@
// Propagated type is [List] here: incorrect.
// Best we can do is [Object]?
return y; // marker
-}''', null, typeProvider.dynamicType);
+}''',
+ null,
+ typeProvider.dynamicType);
}
void fail_mergePropagatedTypesAtJoinPoint_3() {
// https://code.google.com/p/dart/issues/detail?id=19929
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f4(x) {
var y = [];
if (x) {
@@ -11907,12 +12106,15 @@
// A correct answer is the least upper bound of [int] and [double],
// i.e. [num].
return y; // marker
-}''', null, typeProvider.numType);
+}''',
+ null,
+ typeProvider.numType);
}
void fail_mergePropagatedTypesAtJoinPoint_5() {
// https://code.google.com/p/dart/issues/detail?id=19929
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f6(x,y) {
var z = [];
if (x || (z = y) < 0) {
@@ -11922,7 +12124,9 @@
// Propagated type is [List] here: incorrect.
// Best we can do is [Object]?
return z; // marker
-}''', null, typeProvider.dynamicType);
+}''',
+ null,
+ typeProvider.dynamicType);
}
void fail_mergePropagatedTypesAtJoinPoint_7() {
@@ -12162,6 +12366,34 @@
}
}
+ void test_forEach_async() {
+ String code = r'''
+import 'dart:async';
+f(Stream<String> stream) async {
+ await for (var e in stream) {
+ e;
+ }
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ InterfaceType stringType = typeProvider.stringType;
+ // in the declaration
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "e in", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType, same(stringType));
+ }
+ // in the loop body
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "e;", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType, same(stringType));
+ }
+ }
+
void test_functionExpression_asInvocationArgument() {
String code = r'''
class MyMap<K, V> {
@@ -12984,18 +13216,22 @@
}
void test_mergePropagatedTypes_afterIfThen_same() {
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
main() {
var v = 1;
if (v != null) {
v = 2;
}
return v; // marker
-}''', null, typeProvider.intType);
+}''',
+ null,
+ typeProvider.intType);
}
void test_mergePropagatedTypes_afterIfThenElse_different() {
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
main() {
var v = 1;
if (v != null) {
@@ -13004,11 +13240,14 @@
v = '3';
}
return v; // marker
-}''', null, null);
+}''',
+ null,
+ null);
}
void test_mergePropagatedTypes_afterIfThenElse_same() {
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
main() {
var v = 1;
if (v != null) {
@@ -13017,12 +13256,15 @@
v = 3;
}
return v; // marker
-}''', null, typeProvider.intType);
+}''',
+ null,
+ typeProvider.intType);
}
void test_mergePropagatedTypesAtJoinPoint_4() {
// https://code.google.com/p/dart/issues/detail?id=19929
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f5(x) {
var y = [];
if (x) {
@@ -13032,7 +13274,9 @@
}
// Propagated type is [int] here: correct.
return y; // marker
-}''', null, typeProvider.intType);
+}''',
+ null,
+ typeProvider.intType);
}
void test_mutatedOutsideScope() {
@@ -13073,38 +13317,50 @@
// static type of [bool] for [==] comparison and the implementation
// was already consistent with the spec there. But, it's another
// [Object] method, so it's included here.
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f1(x) {
var v = (x == x);
return v; // marker
-}''', null, typeProvider.boolType);
+}''',
+ null,
+ typeProvider.boolType);
}
void test_objectMethodOnDynamicExpression_hashCode() {
// https://code.google.com/p/dart/issues/detail?id=20342
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f1(x) {
var v = x.hashCode;
return v; // marker
-}''', null, typeProvider.intType);
+}''',
+ null,
+ typeProvider.intType);
}
void test_objectMethodOnDynamicExpression_runtimeType() {
// https://code.google.com/p/dart/issues/detail?id=20342
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f1(x) {
var v = x.runtimeType;
return v; // marker
-}''', null, typeProvider.typeType);
+}''',
+ null,
+ typeProvider.typeType);
}
void test_objectMethodOnDynamicExpression_toString() {
// https://code.google.com/p/dart/issues/detail?id=20342
- _assertTypeOfMarkedExpression(r'''
+ _assertTypeOfMarkedExpression(
+ r'''
f1(x) {
var v = x.toString();
return v; // marker
-}''', null, typeProvider.stringType);
+}''',
+ null,
+ typeProvider.stringType);
}
void test_propagatedReturnType_function_hasReturnType_returnsNull() {
@@ -13728,10 +13984,14 @@
ClassElement elementP = ElementFactory.classElement2('P');
FunctionElement elementF = ElementFactory.functionElement('f');
FunctionDeclaration declaration = AstFactory.functionDeclaration(
- AstFactory.typeName4('R'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.typeName4('R'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
AstFactory.formalParameterList([
- AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
- ]), null));
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]),
+ null));
declaration.name.staticElement = elementF;
_resolveNode(declaration, [elementR, elementP]);
expect(declaration.returnType.type, elementR.type);
@@ -13747,10 +14007,14 @@
FunctionElementImpl elementF = ElementFactory.functionElement('f');
elementF.typeParameters = <TypeParameterElement>[elementE];
FunctionDeclaration declaration = AstFactory.functionDeclaration(
- AstFactory.typeName4('E'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.typeName4('E'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
AstFactory.formalParameterList([
- AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
- ]), null));
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]),
+ null));
declaration.name.staticElement = elementF;
_resolveNode(declaration, []);
expect(declaration.returnType.type, elementE.type);
@@ -13775,7 +14039,10 @@
]);
parameterDeclaration.identifier.staticElement = requiredParameter;
FunctionDeclaration declaration = AstFactory.functionDeclaration(
- AstFactory.typeName4('R'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.typeName4('R'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
AstFactory.formalParameterList([parameterDeclaration]), null));
declaration.name.staticElement = elementF;
_resolveNode(declaration, [elementR, elementP]);
@@ -13803,7 +14070,10 @@
]);
parameterDeclaration.identifier.staticElement = requiredParameter;
FunctionDeclaration declaration = AstFactory.functionDeclaration(
- AstFactory.typeName4('R'), null, 'f', AstFactory.functionExpression2(
+ AstFactory.typeName4('R'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
AstFactory.formalParameterList([parameterDeclaration]), null));
declaration.name.staticElement = elementF;
_resolveNode(declaration, [elementR]);
@@ -13827,11 +14097,15 @@
ClassElement elementP = ElementFactory.classElement2('P');
MethodElement elementM = ElementFactory.methodElement('m', null);
elementA.methods = <MethodElement>[elementM];
- MethodDeclaration declaration = AstFactory.methodDeclaration(null,
- AstFactory.typeName4('R'), null, null, AstFactory.identifier3('m'),
+ MethodDeclaration declaration = AstFactory.methodDeclaration(
+ null,
+ AstFactory.typeName4('R'),
+ null,
+ null,
+ AstFactory.identifier3('m'),
AstFactory.formalParameterList([
- AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
- ]));
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]));
declaration.name.staticElement = elementM;
_resolveNode(declaration, [elementA, elementR, elementP]);
expect(declaration.returnType.type, elementR.type);
@@ -13849,11 +14123,15 @@
MethodElementImpl elementM = ElementFactory.methodElement('m', null);
elementM.typeParameters = <TypeParameterElement>[elementE];
elementA.methods = <MethodElement>[elementM];
- MethodDeclaration declaration = AstFactory.methodDeclaration(null,
- AstFactory.typeName4('E'), null, null, AstFactory.identifier3('m'),
+ MethodDeclaration declaration = AstFactory.methodDeclaration(
+ null,
+ AstFactory.typeName4('E'),
+ null,
+ null,
+ AstFactory.identifier3('m'),
AstFactory.formalParameterList([
- AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
- ]));
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]));
declaration.name.staticElement = elementM;
_resolveNode(declaration, [elementA]);
expect(declaration.returnType.type, elementE.type);
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index c1a6603..296be46 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -266,6 +266,25 @@
_assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */");
}
+ void test_comment_multi_lineEnds() {
+ String code = r'''
+/**
+ * aa
+ * bbb
+ * c
+ */''';
+ GatheringErrorListener listener = new GatheringErrorListener();
+ Scanner scanner = new Scanner(null, new CharSequenceReader(code), listener);
+ scanner.tokenize();
+ expect(scanner.lineStarts, equals(<int>[
+ code.indexOf('/**'),
+ code.indexOf(' * aa'),
+ code.indexOf(' * bbb'),
+ code.indexOf(' * c'),
+ code.indexOf(' */')
+ ]));
+ }
+
void test_comment_multi_unterminated() {
_assertError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT, 3, "/* x");
}
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index 7ff5572..36ec73e 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -33,6 +33,12 @@
runPackageMapTests();
}
+Source createSource({String path, String uri}) =>
+ //TODO(pquitslund): find some way to pass an actual URI into source creation
+ new MemoryResourceProvider()
+ .getFile(path)
+ .createSource(uri != null ? Uri.parse(uri) : null);
+
void runPackageMapTests() {
final Uri baseUri = new Uri.file('test/base');
final List<UriResolver> testResolvers = [new FileUriResolver()];
@@ -170,16 +176,13 @@
});
}
-Source createSource({String path, String uri}) => new MemoryResourceProvider()
- .getFile(path)
- .createSource(uri != null ? Uri.parse(uri) : null);
-
class CustomUriResolver extends UriResolver {
String uriPath;
CustomUriResolver({this.uriPath});
@override
- Source resolveAbsolute(Uri uri) => createSource(path: uriPath);
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) =>
+ createSource(path: uriPath);
}
@reflectiveTest
@@ -282,7 +285,7 @@
UriResolver_absolute();
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
invoked = true;
return null;
}
@@ -290,15 +293,15 @@
class UriResolver_nonAbsolute_absolute extends UriResolver {
@override
- Source resolveAbsolute(Uri uri) {
- return new FileBasedSource(new JavaFile.fromUri(uri), uri);
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ return new FileBasedSource(new JavaFile.fromUri(uri), actualUri);
}
}
class UriResolver_nonAbsolute_relative extends UriResolver {
@override
- Source resolveAbsolute(Uri uri) {
- return new FileBasedSource(new JavaFile.fromUri(uri), uri);
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ return new FileBasedSource(new JavaFile.fromUri(uri), actualUri);
}
}
@@ -308,7 +311,7 @@
UriResolver_restoreUri(this.source1, this.expected1);
@override
- Source resolveAbsolute(Uri uri) => null;
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) => null;
@override
Uri restoreAbsolute(Source source) {
@@ -325,7 +328,7 @@
UriResolver_SourceFactoryTest_test_fromEncoding_valid(this.encoding);
@override
- Source resolveAbsolute(Uri uri) {
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (uri.toString() == encoding) {
return new TestSource();
}
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 a346a87..b49a115 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -1391,14 +1391,12 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
}
- void test_undefinedGetter_static_conditionalAccess() {
- // The conditional access operator '?.' cannot be used to access static
- // fields.
+ void test_undefinedGetter_typeLiteral_conditionalAccess() {
+ // When applied to a type literal, the conditional access operator '?.'
+ // cannot be used to access instance getters of Type.
Source source = addSource('''
-class A {
- static var x;
-}
-var a = A?.x;
+class A {}
+f() => A?.hashCode;
''');
computeLibrarySourceErrors(source);
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
@@ -1562,14 +1560,12 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
}
- void test_undefinedMethod_static_conditionalAccess() {
- // The conditional access operator '?.' cannot be used to access static
- // methods.
+ void test_undefinedMethod_typeLiteral_conditionalAccess() {
+ // When applied to a type literal, the conditional access operator '?.'
+ // cannot be used to access instance methods of Type.
Source source = addSource('''
-class A {
- static void m() {}
-}
-f() { A?.m(); }
+class A {}
+f() => A?.toString();
''');
computeLibrarySourceErrors(source);
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
@@ -1651,19 +1647,6 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
}
- void test_undefinedSetter_static_conditionalAccess() {
- // The conditional access operator '?.' cannot be used to access static
- // fields.
- Source source = addSource('''
-class A {
- static var x;
-}
-f() { A?.x = 1; }
-''');
- computeLibrarySourceErrors(source);
- assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
- }
-
void test_undefinedSetter_void() {
Source source = addSource(r'''
class T {
diff --git a/pkg/analyzer/test/source/path_filter_test.dart b/pkg/analyzer/test/source/path_filter_test.dart
index 6b0131a..4542e99 100644
--- a/pkg/analyzer/test/source/path_filter_test.dart
+++ b/pkg/analyzer/test/source/path_filter_test.dart
@@ -4,46 +4,47 @@
library test.source.path_filter;
-import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/path_filter.dart';
+import 'package:path/path.dart';
import 'package:unittest/unittest.dart';
main() {
groupSep = ' | ';
group('PathFilterTest', () {
- setUp(() { });
- tearDown(() { });
+ setUp(() {});
+ tearDown(() {});
test('test_ignoreEverything', () {
- var filter = new PathFilter('/', ['*']);
+ var filter = new PathFilter(context, '/', ['*']);
expect(filter.ignored('a'), isTrue);
});
test('test_ignoreFile', () {
- var filter = new PathFilter('/', ['apple']);
+ var filter = new PathFilter(context, '/', ['apple']);
expect(filter.ignored('apple'), isTrue);
expect(filter.ignored('banana'), isFalse);
});
test('test_ignoreMultipleFiles', () {
- var filter = new PathFilter('/', ['apple', 'banana']);
+ var filter = new PathFilter(context, '/', ['apple', 'banana']);
expect(filter.ignored('apple'), isTrue);
expect(filter.ignored('banana'), isTrue);
});
test('test_ignoreSubDir', () {
- var filter = new PathFilter('/', ['apple/*']);
+ var filter = new PathFilter(context, '/', ['apple/*']);
expect(filter.ignored('apple/banana'), isTrue);
expect(filter.ignored('apple/banana/cantaloupe'), isFalse);
});
test('test_ignoreTree', () {
- var filter = new PathFilter('/', ['apple/**']);
+ var filter = new PathFilter(context, '/', ['apple/**']);
expect(filter.ignored('apple/banana'), isTrue);
expect(filter.ignored('apple/banana/cantaloupe'), isTrue);
});
test('test_ignoreSdkExt', () {
- var filter = new PathFilter('/', ['sdk_ext/**']);
+ var filter = new PathFilter(context, '/', ['sdk_ext/**']);
expect(filter.ignored('sdk_ext/entry.dart'), isTrue);
expect(filter.ignored('sdk_ext/lib/src/part.dart'), isTrue);
});
test('test_outsideRoot', () {
- var filter = new PathFilter('/workspace/dart/sdk', ['sdk_ext/**']);
+ var filter =
+ new PathFilter(context, '/workspace/dart/sdk', ['sdk_ext/**']);
expect(filter.ignored('/'), isTrue);
expect(filter.ignored('/workspace'), isTrue);
expect(filter.ignored('/workspace/dart'), isTrue);
@@ -51,7 +52,8 @@
expect(filter.ignored('/workspace/dart/../dart/sdk'), isFalse);
});
test('test_relativePaths', () {
- var filter = new PathFilter('/workspace/dart/sdk', ['sdk_ext/**']);
+ var filter =
+ new PathFilter(context, '/workspace/dart/sdk', ['sdk_ext/**']);
expect(filter.ignored('../apple'), isTrue);
expect(filter.ignored('../sdk/main.dart'), isFalse);
expect(filter.ignored('../sdk/sdk_ext/entry.dart'), isTrue);
diff --git a/pkg/compiler/lib/compiler_new.dart b/pkg/compiler/lib/compiler_new.dart
index 3ec05ec..7d4ef18 100644
--- a/pkg/compiler/lib/compiler_new.dart
+++ b/pkg/compiler/lib/compiler_new.dart
@@ -67,7 +67,12 @@
/// zero-based character offsets from the beginning of the compilation unit.
/// [message] is the diagnostic message, and [kind] indicates indicates what
/// kind of diagnostic it is.
- void report(Uri uri, int begin, int end, String message, Diagnostic kind);
+ ///
+ /// Experimental: [code] gives access to an id for the messages. Currently it
+ /// is the [Message] used to create the diagnostic, if available, from which
+ /// the [MessageKind] is accessible.
+ void report(var code,
+ Uri uri, int begin, int end, String text, Diagnostic kind);
}
/// Information resulting from the compilation.
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index cac25b1..808f88f1 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -196,7 +196,8 @@
}
void log(message) {
- callUserHandler(null, null, null, message, api.Diagnostic.VERBOSE_INFO);
+ callUserHandler(
+ null, null, null, null, message, api.Diagnostic.VERBOSE_INFO);
}
/// See [leg.Compiler.translateResolvedUri].
@@ -427,9 +428,10 @@
// [:span.uri:] might be [:null:] in case of a [Script] with no [uri]. For
// instance in the [Types] constructor in typechecker.dart.
if (span == null || span.uri == null) {
- callUserHandler(null, null, null, '$message', kind);
+ callUserHandler(message, null, null, null, '$message', kind);
} else {
- callUserHandler(span.uri, span.begin, span.end, '$message', kind);
+ callUserHandler(
+ message, span.uri, span.begin, span.end, '$message', kind);
}
}
@@ -438,11 +440,11 @@
&& (options.indexOf('--allow-mock-compilation') != -1);
}
- void callUserHandler(Uri uri, int begin, int end,
- String message, api.Diagnostic kind) {
+ void callUserHandler(leg.Message message, Uri uri, int begin, int end,
+ String text, api.Diagnostic kind) {
try {
userHandlerTask.measure(() {
- handler.report(uri, begin, end, message, kind);
+ handler.report(message, uri, begin, end, text, kind);
});
} catch (ex, s) {
diagnoseCrashInUserCode(
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 4b0be2d..b203ec1 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -336,6 +336,8 @@
ConstantSystem get constantSystem => handler.constantSystem;
AstConstant evaluate(Node node) {
+ // TODO(johnniwinther): should there be a visitErrorNode?
+ if (node is ErrorNode) return new ErroneousAstConstant(context, node);
return node.accept(this);
}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index d35e501..1ed9781 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -1162,14 +1162,17 @@
void unhandledExceptionOnElement(Element element) {
if (hasCrashed) return;
hasCrashed = true;
- reportDiagnostic(element,
- MessageKind.COMPILER_CRASHED.message(),
- api.Diagnostic.CRASH);
+ reportDiagnostic(
+ element,
+ MessageTemplate.TEMPLATES[MessageKind.COMPILER_CRASHED].message(),
+ api.Diagnostic.CRASH);
pleaseReportCrash();
}
void pleaseReportCrash() {
- print(MessageKind.PLEASE_REPORT_THE_CRASH.message({'buildId': buildId}));
+ print(
+ MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
+ .message({'buildId': buildId}));
}
SourceSpan spanFromSpannable(Spannable node) {
@@ -1225,7 +1228,8 @@
void log(message) {
reportDiagnostic(null,
- MessageKind.GENERIC.message({'text': '$message'}),
+ MessageTemplate.TEMPLATES[MessageKind.GENERIC]
+ .message({'text': '$message'}),
api.Diagnostic.VERBOSE_INFO);
}
@@ -1239,9 +1243,11 @@
if (error is SpannableAssertionFailure) {
reportAssertionFailure(error);
} else {
- reportDiagnostic(new SourceSpan(uri, 0, 0),
- MessageKind.COMPILER_CRASHED.message(),
- api.Diagnostic.CRASH);
+ reportDiagnostic(
+ new SourceSpan(uri, 0, 0),
+ MessageTemplate.TEMPLATES[MessageKind.COMPILER_CRASHED]
+ .message(),
+ api.Diagnostic.CRASH);
}
pleaseReportCrash();
}
@@ -1379,7 +1385,7 @@
reportWarning(NO_LOCATION_SPANNABLE,
MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
{'importChain': importChains.join(
- MessageKind.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
+ MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
}
}
@@ -1615,11 +1621,13 @@
} else if (info.hints == 0) {
kind = MessageKind.HIDDEN_WARNINGS;
}
+ MessageTemplate template = MessageTemplate.TEMPLATES[kind];
reportDiagnostic(null,
- kind.message({'warnings': info.warnings,
- 'hints': info.hints,
- 'uri': uri},
- terseDiagnostics),
+ template.message(
+ {'warnings': info.warnings,
+ 'hints': info.hints,
+ 'uri': uri},
+ terseDiagnostics),
api.Diagnostic.HINT);
});
}
@@ -1897,8 +1905,11 @@
}
}
lastDiagnosticWasFiltered = false;
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
reportDiagnostic(
- node, messageKind.message(arguments, terseDiagnostics), kind);
+ node,
+ template.message(arguments, terseDiagnostics),
+ kind);
}
void reportDiagnostic(Spannable span,
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index db1ea0b..0c8e027 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -109,7 +109,7 @@
/// Invoke a built-in operator.
Primitive applyBuiltin(BuiltinOperator op, List<Primitive> args) {
- return letPrim(new ApplyBuiltinOperator(op, args));
+ return letPrim(new ApplyBuiltinOperator(op, args, sourceInformation));
}
/// Inserts an invocation. binds its continuation, and returns the
@@ -258,10 +258,10 @@
}
/// Puts the given fragment into this one.
- ///
+ ///
/// If [other] was an open fragment, its hole becomes the new hole
/// in this fragment.
- ///
+ ///
/// [other] is reset to an empty fragment after this.
void append(CpsFragment other) {
if (other.root == null) return;
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 7117c80..4ec13ad 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -638,7 +638,7 @@
Selector selector,
TypeMask mask,
List<ir.Primitive> arguments,
- {SourceInformation sourceInformation}) {
+ SourceInformation sourceInformation) {
assert(isOpen);
return _continueWithExpression(
(k) => new ir.InvokeMethod(receiver, selector, mask, arguments, k,
@@ -651,8 +651,8 @@
List<ir.Definition> arguments,
{SourceInformation sourceInformation}) {
Selector selector = callStructure.callSelector;
- return _buildInvokeDynamic(target, selector, mask, arguments,
- sourceInformation: sourceInformation);
+ return _buildInvokeDynamic(
+ target, selector, mask, arguments, sourceInformation);
}
@@ -877,15 +877,15 @@
List<ir.Primitive> arguments,
{SourceInformation sourceInformation}) {
return _buildInvokeDynamic(
- receiver, selector, mask, arguments,
- sourceInformation: sourceInformation);
+ receiver, selector, mask, arguments, sourceInformation);
}
/// Create a dynamic getter invocation on [receiver] where the getter name is
/// defined by [selector].
ir.Primitive buildDynamicGet(ir.Primitive receiver,
Selector selector,
- TypeMask mask) {
+ TypeMask mask,
+ SourceInformation sourceInformation) {
assert(selector.isGetter);
FieldElement field = program.locateSingleField(selector, mask);
if (field != null) {
@@ -894,7 +894,7 @@
return buildFieldGet(receiver, field);
} else {
return _buildInvokeDynamic(
- receiver, selector, mask, const <ir.Primitive>[]);
+ receiver, selector, mask, const <ir.Primitive>[], sourceInformation);
}
}
@@ -903,7 +903,8 @@
ir.Primitive buildDynamicSet(ir.Primitive receiver,
Selector selector,
TypeMask mask,
- ir.Primitive value) {
+ ir.Primitive value,
+ {SourceInformation sourceInformation}) {
assert(selector.isSetter);
FieldElement field = program.locateSingleField(selector, mask);
if (field != null) {
@@ -911,19 +912,22 @@
// treated as a field access, since the setter might not be emitted.
buildFieldSet(receiver, field, value);
} else {
- _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value]);
+ _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value],
+ sourceInformation);
}
return value;
}
/// Create a dynamic index set invocation on [receiver] with the provided
/// [index] and [value].
- ir.Primitive buildDynamicIndexSet(ir.Primitive receiver,
- TypeMask mask,
- ir.Primitive index,
- ir.Primitive value) {
+ ir.Primitive buildDynamicIndexSet(ir.Primitive receiver,
+ TypeMask mask,
+ ir.Primitive index,
+ ir.Primitive value,
+ {SourceInformation sourceInformation}) {
_buildInvokeDynamic(
- receiver, new Selector.indexSet(), mask, <ir.Primitive>[index, value]);
+ receiver, new Selector.indexSet(), mask, <ir.Primitive>[index, value],
+ sourceInformation);
return value;
}
@@ -1043,11 +1047,13 @@
///
/// The arguments must be strings; usually a call to [buildStringify] is
/// needed to ensure the proper conversion takes places.
- ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) {
+ ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments,
+ {SourceInformation sourceInformation}) {
assert(isOpen);
return addPrimitive(new ir.ApplyBuiltinOperator(
ir.BuiltinOperator.StringConcatenate,
- arguments));
+ arguments,
+ sourceInformation));
}
/// Create an invocation of the `call` method of [functionExpression], where
@@ -1829,8 +1835,10 @@
ir.Expression buildCatchClause(CatchClauseInfo clause) {
IrBuilder clauseBuilder = builder.makeDelimitedBuilder();
- clauseBuilder.declareLocalVariable(clause.exceptionVariable,
- initialValue: exceptionParameter);
+ if (clause.exceptionVariable != null) {
+ clauseBuilder.declareLocalVariable(clause.exceptionVariable,
+ initialValue: exceptionParameter);
+ }
if (clause.stackTraceVariable != null) {
clauseBuilder.declareLocalVariable(clause.stackTraceVariable,
initialValue: traceParameter);
@@ -2098,7 +2106,10 @@
ir.Primitive buildNonTailThrow(ir.Primitive value) {
assert(isOpen);
- return addPrimitive(new ir.NonTailThrow(value));
+ ir.Parameter param = new ir.Parameter(null);
+ ir.Continuation cont = new ir.Continuation(<ir.Parameter>[param]);
+ add(new ir.LetCont(cont, new ir.Throw(value)));
+ return param;
}
void buildRethrow() {
@@ -2215,9 +2226,11 @@
return environment.discard(1);
}
- ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) {
+ ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y,
+ {SourceInformation sourceInformation}) {
return addPrimitive(new ir.ApplyBuiltinOperator(
- ir.BuiltinOperator.Identical, <ir.Primitive>[x, y]));
+ ir.BuiltinOperator.Identical, <ir.Primitive>[x, y],
+ sourceInformation));
}
/// Called when entering a nested function with free variables.
@@ -2659,8 +2672,10 @@
/// `right` if [value] is null. Only when [value] is null, [buildRight] is
/// evaluated to produce the `right` value.
ir.Primitive buildIfNull(ir.Primitive value,
- ir.Primitive buildRight(IrBuilder builder)) {
- ir.Primitive condition = _buildCheckNull(value);
+ ir.Primitive buildRight(IrBuilder builder),
+ {SourceInformation sourceInformation}) {
+ ir.Primitive condition =
+ _buildCheckNull(value, sourceInformation: sourceInformation);
return buildConditional(condition, buildRight, (_) => value);
}
@@ -2668,15 +2683,19 @@
/// that checks if [receiver] is null, if so, it returns null, otherwise it
/// evaluates the [buildSend] expression.
ir.Primitive buildIfNotNullSend(ir.Primitive receiver,
- ir.Primitive buildSend(IrBuilder builder)) {
- ir.Primitive condition = _buildCheckNull(receiver);
+ ir.Primitive buildSend(IrBuilder builder),
+ {SourceInformation sourceInformation}) {
+ ir.Primitive condition =
+ _buildCheckNull(receiver, sourceInformation: sourceInformation);
return buildConditional(condition, (_) => receiver, buildSend);
}
/// Creates a type test checking whether [value] is null.
- ir.Primitive _buildCheckNull(ir.Primitive value) {
+ ir.Primitive _buildCheckNull(ir.Primitive value,
+ {SourceInformation sourceInformation}) {
assert(isOpen);
- return buildIdentical(value, buildNullConstant());
+ return buildIdentical(value, buildNullConstant(),
+ sourceInformation: sourceInformation);
}
/// Convert the given value to a string.
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 2ce1b01..238a3fc 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
@@ -95,6 +95,7 @@
with IrBuilderMixin<ast.Node>,
SemanticSendResolvedMixin<ir.Primitive, dynamic>,
SendResolverMixin,
+ ErrorBulkMixin<ir.Primitive, dynamic>,
BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>,
BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>,
BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>,
@@ -453,8 +454,10 @@
visitTryStatement(ast.TryStatement node) {
List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[];
for (ast.CatchBlock catchClause in node.catchBlocks.nodes) {
- assert(catchClause.exception != null);
- LocalVariableElement exceptionVariable = elements[catchClause.exception];
+ LocalVariableElement exceptionVariable;
+ if (catchClause.exception != null) {
+ exceptionVariable = elements[catchClause.exception];
+ }
LocalVariableElement stackTraceVariable;
if (catchClause.trace != null) {
stackTraceVariable = elements[catchClause.trace];
@@ -606,7 +609,7 @@
} else {
// The call to assert and its argument expression must be ignored
// in production mode.
- // Assertions can onl)y occur in expression statements, so no value needs
+ // Assertions can only occur in expression statements, so no value needs
// to be returned.
return null;
}
@@ -665,7 +668,8 @@
return irBuilder.buildDynamicGet(
translateReceiver(receiver),
selector,
- elements.getTypeMask(node));
+ elements.getTypeMask(node),
+ sourceInformationBuilder.buildGet(node));
}
@override
@@ -678,7 +682,8 @@
return irBuilder.buildIfNotNullSend(
target,
nested(() => irBuilder.buildDynamicGet(
- target, selector, elements.getTypeMask(node))));
+ target, selector, elements.getTypeMask(node),
+ sourceInformationBuilder.buildGet(node))));
}
@override
@@ -886,7 +891,9 @@
List<ir.Primitive> arguments = <ir.Primitive>[visit(index)];
arguments = normalizeDynamicArguments(selector.callStructure, arguments);
return irBuilder.buildDynamicInvocation(
- target, selector, elements.getTypeMask(node), arguments);
+ target, selector, elements.getTypeMask(node), arguments,
+ sourceInformation:
+ sourceInformationBuilder.buildCall(receiver, node.selector));
}
ir.Primitive translateSuperBinary(FunctionElement function,
@@ -971,7 +978,9 @@
Selector selector = operator.selector;
ir.Primitive receiver = translateReceiver(expression);
return irBuilder.buildDynamicInvocation(
- receiver, selector, elements.getTypeMask(node), const []);
+ receiver, selector, elements.getTypeMask(node), const [],
+ sourceInformation: sourceInformationBuilder.buildCall(
+ expression, node));
}
@override
@@ -1254,10 +1263,10 @@
}
ir.Primitive translateCompounds(
+ ast.SendSet node,
{ir.Primitive getValue(),
CompoundRhs rhs,
- void setValue(ir.Primitive value),
- TypeMask operatorTypeMask}) {
+ void setValue(ir.Primitive value)}) {
ir.Primitive value = getValue();
op.BinaryOperator operator = rhs.operator;
if (operator.kind == op.BinaryOperatorKind.IF_NULL) {
@@ -1281,9 +1290,13 @@
List<ir.Primitive> arguments = <ir.Primitive>[rhsValue];
arguments = normalizeDynamicArguments(
operatorSelector.callStructure, arguments);
- ir.Primitive result =
- irBuilder.buildDynamicInvocation(
- value, operatorSelector, operatorTypeMask, arguments);
+ TypeMask operatorTypeMask =
+ elements.getOperatorTypeMaskInComplexSendSet(node);
+ SourceInformation operatorSourceInformation =
+ sourceInformationBuilder.buildCall(node, node.assignmentOperator);
+ ir.Primitive result = irBuilder.buildDynamicInvocation(
+ value, operatorSelector, operatorTypeMask, arguments,
+ sourceInformation: operatorSourceInformation);
setValue(result);
return rhs.kind == CompoundKind.POSTFIX ? value : result;
}
@@ -1378,13 +1391,13 @@
CompoundRhs rhs,
arg) {
return translateCompounds(
+ node,
getValue: () {
return buildConstantExpression(constant,
sourceInformationBuilder.buildGet(node));
},
rhs: rhs,
- setValue: (value) {}, // The binary operator will throw before this.
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ setValue: (value) {}); // The binary operator will throw before this.
}
@override
@@ -1398,16 +1411,17 @@
ir.Primitive target = translateReceiver(receiver);
ir.Primitive helper() {
return translateCompounds(
+ node,
getValue: () => irBuilder.buildDynamicGet(
target,
getterSelector,
- elements.getGetterTypeMaskInComplexSendSet(node)),
+ elements.getGetterTypeMaskInComplexSendSet(node),
+ sourceInformationBuilder.buildGet(node)),
rhs: rhs,
setValue: (ir.Primitive result) {
irBuilder.buildDynamicSet(
target, setterSelector, elements.getTypeMask(node), result);
- },
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ });
}
return node.isConditional
? irBuilder.buildIfNotNullSend(target, nested(helper))
@@ -1427,6 +1441,7 @@
arg,
{bool isSetterValid}) {
return translateCompounds(
+ node,
getValue: () {
if (local.isFunction) {
return irBuilder.buildLocalFunctionGet(local);
@@ -1441,8 +1456,7 @@
} else {
return buildLocalNoSuchSetter(local, result);
}
- },
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ });
}
ir.Primitive buildStaticNoSuchGetter(Element element) {
@@ -1467,6 +1481,7 @@
CompoundRhs rhs,
arg) {
return translateCompounds(
+ node,
getValue: () {
switch (getterKind) {
case CompoundGetter.FIELD:
@@ -1493,8 +1508,7 @@
return buildStaticNoSuchSetter(
setter != null ? setter : getter, result);
}
- },
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ });
}
ir.Primitive buildSuperNoSuchGetter(Element element, TypeMask mask) {
@@ -1523,6 +1537,7 @@
CompoundRhs rhs,
arg) {
return translateCompounds(
+ node,
getValue: () {
switch (getterKind) {
case CompoundGetter.FIELD:
@@ -1550,8 +1565,7 @@
return buildSuperNoSuchSetter(
setter, elements.getTypeMask(node), result);
}
- },
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ });
}
@override
@@ -1561,14 +1575,14 @@
CompoundRhs rhs,
arg) {
return translateCompounds(
+ node,
getValue: () {
return irBuilder.buildReifyTypeVariable(
typeVariable.type,
sourceInformationBuilder.buildGet(node));
},
rhs: rhs,
- setValue: (value) {}, // The binary operator will throw before this.
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ setValue: (value) {}); // The binary operator will throw before this.
}
@override
@@ -1581,6 +1595,7 @@
ir.Primitive target = visit(receiver);
ir.Primitive indexValue = visit(index);
return translateCompounds(
+ node,
getValue: () {
Selector selector = new Selector.index();
List<ir.Primitive> arguments = <ir.Primitive>[indexValue];
@@ -1590,7 +1605,9 @@
target,
selector,
elements.getGetterTypeMaskInComplexSendSet(node),
- arguments);
+ arguments,
+ sourceInformation:
+ sourceInformationBuilder.buildCall(receiver, node));
},
rhs: rhs,
setValue: (ir.Primitive result) {
@@ -1599,8 +1616,7 @@
elements.getTypeMask(node),
indexValue,
result);
- },
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ });
}
@override
@@ -1615,6 +1631,7 @@
bool isSetterValid}) {
ir.Primitive indexValue = visit(index);
return translateCompounds(
+ node,
getValue: () {
if (isGetterValid) {
return irBuilder.buildSuperIndex(indexFunction, indexValue);
@@ -1635,8 +1652,7 @@
elements.getTypeMask(node),
<ir.Primitive>[indexValue, result]);
}
- },
- operatorTypeMask: elements.getOperatorTypeMaskInComplexSendSet(node));
+ });
}
/// Evaluates a string interpolation and appends each part to [accumulator]
@@ -1707,17 +1723,6 @@
ir.Primitive buildAbstractClassInstantiationError(ClassElement element);
@override
- ir.Primitive errorInvalidAssert(
- ast.Send node,
- ast.NodeList arguments, _) {
- if (compiler.enableUserAssertions) {
- return giveup(node, 'Assert');
- } else {
- return irBuilder.buildNullConstant();
- }
- }
-
- @override
ir.Primitive visitUnresolvedCompound(
ast.Send node,
Element element,
@@ -1763,17 +1768,6 @@
}
@override
- ir.Primitive errorNonConstantConstructorInvoke(
- ast.NewExpression node,
- Element element,
- DartType type,
- ast.NodeList arguments,
- CallStructure callStructure, _) {
- assert(compiler.compilationFailed);
- return irBuilder.buildNullConstant();
- }
-
- @override
ir.Primitive visitUnresolvedGet(
ast.Send node,
Element element, _) {
@@ -1844,20 +1838,12 @@
}
@override
- ir.Primitive errorUndefinedBinaryExpression(
- ast.Send node,
- ast.Node left,
- ast.Operator operator,
- ast.Node right, _) {
- assert(compiler.compilationFailed);
- return irBuilder.buildNullConstant();
+ ir.Primitive bulkHandleNode(ast.Node node, String message, _) {
+ return giveup(node, "Unhandled node: ${message.replaceAll('#', '$node')}");
}
@override
- ir.Primitive errorUndefinedUnaryExpression(
- ast.Send node,
- ast.Operator operator,
- ast.Node expression, _) {
+ ir.Primitive bulkHandleError(ast.Send node, ErroneousElement error, _) {
assert(compiler.compilationFailed);
return irBuilder.buildNullConstant();
}
@@ -2422,7 +2408,6 @@
default:
compiler.internalError(element, "Unexpected element type $element");
}
- new CleanupPass().visit(root);
return root;
});
}
@@ -3357,49 +3342,3 @@
}
}
}
-
-/// Perform simple post-processing on the initial CPS-translated root term.
-///
-/// This pass performs backend-independent post-processing on the translated
-/// term. It is implemented separately from the optimization passes because
-/// it is required for correctness of the implementation.
-///
-/// It performs the following translations:
-/// - Replace [ir.LetPrim] binding a [ir.NonTailThrow] with a [ir.Throw]
-/// expression.
-class CleanupPass extends ir.RecursiveVisitor {
- ir.Expression replacementFor(ir.Expression expression) {
- if (expression != null && expression is ir.LetPrim) {
- ir.Primitive primitive = expression.primitive;
- if (primitive is ir.NonTailThrow) {
- ir.RemovalVisitor.remove(expression);
- return new ir.Throw(primitive.value.definition);
- }
- }
- return expression;
- }
-
- processFunctionDefinition(ir.FunctionDefinition node) {
- node.body = replacementFor(node.body);
- }
-
- processLetPrim(ir.LetPrim node) {
- node.body = replacementFor(node.body);
- }
-
- processLetCont(ir.LetCont node) {
- node.body = replacementFor(node.body);
- }
-
- processLetHandler(ir.LetHandler node) {
- node.body = replacementFor(node.body);
- }
-
- processLetMutable(ir.LetMutable node) {
- node.body = replacementFor(node.body);
- }
-
- processContinuation(ir.Continuation node) {
- node.body = replacementFor(node.body);
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
index 0d7c066..88faa4d 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
@@ -32,19 +32,9 @@
Map<Definition, Set<Reference>> seenReferences =
<Definition, Set<Reference>>{};
- Map<Definition, Node> bindings = <Definition, Node>{};
+ Set<Definition> inScope = new Set<Definition>();
Set<Continuation> insideContinuations = new Set<Continuation>();
- doInScope(Iterable<Definition> defs, Node binding, action()) {
- for (Definition def in defs) {
- bindings[def] = binding;
- }
- action();
- for (Definition def in defs) {
- bindings.remove(def);
- }
- }
-
void markAsSeen(Definition def) {
if (!seenDefinitions.add(def)) {
error('Redeclared $def', def);
@@ -52,70 +42,92 @@
seenReferences[def] = new Set<Reference>();
}
- @override
- visitLetCont(LetCont node) {
- // Analyze each continuation separately without the others in scope.
- for (Continuation continuation in node.continuations) {
- // We always consider a continuation to be in scope of itself.
- // The isRecursive flag is checked explicitly to give more useful
- // error messages.
- doInScope([continuation], node, () => visit(continuation));
- }
- // Analyze the body with all continuations in scope.
- doInScope(node.continuations, node, () => visit(node.body));
+ void enterScope(Iterable<Definition> definitions) {
+ inScope.addAll(definitions);
+ pushAction(() => inScope.removeAll(definitions));
+ }
+
+ void enterContinuation(Continuation cont) {
+ insideContinuations.add(cont);
+ pushAction(() => insideContinuations.remove(cont));
+ }
+
+ void check(FunctionDefinition node) {
+ topLevelNode = node;
+ visit(node);
+ // Check for broken reference chains. We check this last, so out-of-scope
+ // references are not classified as a broken reference chain.
+ seenDefinitions.forEach(checkReferenceChain);
}
@override
- visitContinuation(Continuation node) {
- markAsSeen(node);
- if (node.isReturnContinuation) {
- error('Non-return continuation missing body', node);
- }
- node.parameters.forEach(markAsSeen);
- insideContinuations.add(node);
- doInScope(node.parameters, node, () => visit(node.body));
- insideContinuations.remove(node);
+ Expression traverseLetCont(LetCont node) {
+ node.continuations.forEach(markAsSeen);
+ node.continuations.forEach(push);
+
+ // Put all continuations in scope when visiting the body.
+ enterScope(node.continuations);
+
+ return node.body;
}
@override
- visitLetPrim(LetPrim node) {
+ Expression traverseLetPrim(LetPrim node) {
markAsSeen(node.primitive);
+
+ // Process references in the primitive.
visit(node.primitive);
- doInScope([node.primitive], node, () => visit(node.body));
+
+ // Put the primitive in scope when visiting the body.
+ enterScope([node.primitive]);
+
+ return node.body;
}
@override
- visitLetMutable(LetMutable node) {
+ Expression traverseLetMutable(LetMutable node) {
markAsSeen(node.variable);
processReference(node.value);
- doInScope([node.variable], node, () => visit(node.body));
+
+ // Put the primitive in scope when visiting the body.
+ enterScope([node.variable]);
+
+ return node.body;
+ }
+
+ @override
+ Expression traverseContinuation(Continuation cont) {
+ if (cont.isReturnContinuation) {
+ error('Non-return continuation missing body', cont);
+ }
+ cont.parameters.forEach(markAsSeen);
+ enterScope(cont.parameters);
+ // Put every continuation in scope at its own body. The isRecursive
+ // flag is checked explicitly using [insideContinuations].
+ enterScope([cont]);
+ enterContinuation(cont);
+ return cont.body;
}
@override
visitFunctionDefinition(FunctionDefinition node) {
if (node.thisParameter != null) {
markAsSeen(node.thisParameter);
+ enterScope([node.thisParameter]);
}
node.parameters.forEach(markAsSeen);
+ enterScope(node.parameters);
markAsSeen(node.returnContinuation);
+ enterScope([node.returnContinuation]);
if (!node.returnContinuation.isReturnContinuation) {
error('Return continuation with a body', node);
}
- doInOptionalScope(node.thisParameter, node,
- () => doInScope(node.parameters, node,
- () => doInScope([node.returnContinuation], node,
- () => visit(node.body))));
- }
-
- doInOptionalScope(Parameter parameter, Node node, action) {
- return (parameter == null)
- ? action()
- : doInScope([parameter], node, action);
+ visit(node.body);
}
@override
processReference(Reference reference) {
- if (!bindings.containsKey(reference.definition)) {
+ if (!inScope.contains(reference.definition)) {
error('Referenced out of scope: ${reference.definition}', reference);
}
if (!seenReferences[reference.definition].add(reference)) {
@@ -181,13 +193,4 @@
'$sexpr\n';
}
- void check(FunctionDefinition node) {
- topLevelNode = node;
- visit(node);
-
- // Check this last, so out-of-scope references are not classified as
- // a broken reference chain.
- seenDefinitions.forEach(checkReferenceChain);
- }
-
}
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 98d9a35..53960b5 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -45,7 +45,7 @@
Expression plug(Expression expr) => throw 'impossible';
/// The next expression in the basic block.
- ///
+ ///
/// For [InteriorExpression]s this is the body, for [CallExpressions] it is
/// the body of the continuation, and for [TailExpressions] it is `null`.
Expression get next;
@@ -66,7 +66,7 @@
/// An expression that creates new bindings and continues evaluation in
/// a subexpression.
-///
+///
/// The interior expressions are [LetPrim], [LetCont], [LetHandler], and
/// [LetMutable].
abstract class InteriorExpression extends Expression implements InteriorNode {
@@ -145,6 +145,10 @@
/// True if time-of-evaluation is irrelevant for the given primitive,
/// assuming its inputs are the same values.
bool get isSafeForReordering;
+
+ /// The source information associated with this primitive.
+ // TODO(johnniwinther): Require source information for all primitives.
+ SourceInformation get sourceInformation => null;
}
/// Operands to invocations and primitives are always variables. They point to
@@ -351,7 +355,7 @@
this.mask,
this.arguments,
this.continuation,
- [this.sourceInformation]);
+ this.sourceInformation);
accept(Visitor visitor) => visitor.visitInvokeMethod(this);
}
@@ -502,8 +506,11 @@
class ApplyBuiltinOperator extends Primitive {
BuiltinOperator operator;
List<Reference<Primitive>> arguments;
+ final SourceInformation sourceInformation;
- ApplyBuiltinOperator(this.operator, List<Primitive> arguments)
+ ApplyBuiltinOperator(this.operator,
+ List<Primitive> arguments,
+ this.sourceInformation)
: this.arguments = _referenceList(arguments);
accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
@@ -533,23 +540,6 @@
accept(Visitor visitor) => visitor.visitRethrow(this);
}
-/// A throw occurring in non-tail position.
-///
-/// The CPS translation of an expression produces a primitive as the value
-/// of the expression. For convenience in the implementation of the
-/// translation, a [NonTailThrow] is used as that value. A cleanup pass
-/// removes these and replaces them with [Throw] expressions.
-class NonTailThrow extends Primitive {
- final Reference<Primitive> value;
-
- NonTailThrow(Primitive value) : value = new Reference<Primitive>(value);
-
- accept(Visitor visitor) => visitor.visitNonTailThrow(this);
-
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-}
-
/// An expression that is known to be unreachable.
///
/// This can be placed as the body of a call continuation, when the caller is
@@ -673,7 +663,7 @@
this.value = new Reference<Primitive>(value);
accept(Visitor visitor) => visitor.visitSetField(this);
-
+
bool get isSafeForElimination => false;
bool get isSafeForReordering => false;
}
@@ -850,10 +840,11 @@
class Interceptor extends Primitive {
final Reference<Primitive> input;
final Set<ClassElement> interceptedClasses = new Set<ClassElement>();
+ final SourceInformation sourceInformation;
- Interceptor(Primitive input)
+ Interceptor(Primitive input, this.sourceInformation)
: this.input = new Reference<Primitive>(input);
-
+
accept(Visitor visitor) => visitor.visitInterceptor(this);
bool get isSafeForElimination => true;
@@ -1137,7 +1128,6 @@
T visitParameter(Parameter node);
T visitContinuation(Continuation node);
T visitMutableVariable(MutableVariable node);
- T visitNonTailThrow(NonTailThrow node);
T visitGetStatic(GetStatic node);
T visitInterceptor(Interceptor node);
T visitCreateInstance(CreateInstance node);
@@ -1160,10 +1150,16 @@
T visitForeignCode(ForeignCode node);
}
-/// Recursively visits the entire CPS term, and calls abstract `process*`
-/// (i.e. `processLetPrim`) functions in pre-order.
-class RecursiveVisitor implements Visitor {
- const RecursiveVisitor();
+/// Visits all non-recursive children of a CPS term, i.e. anything
+/// not of type [Expression] or [Continuation].
+///
+/// Note that the non-recursive nodes can contain other nodes inside of them,
+/// e.g. [Branch] contains an [IsTrue] which contains a [Reference].
+///
+/// The `process*` methods are called in pre-order for every node visited.
+/// These can be overridden without disrupting the visitor traversal.
+class LeafVisitor implements Visitor {
+ const LeafVisitor();
visit(Node node) => node.accept(this);
@@ -1175,7 +1171,6 @@
if (node.thisParameter != null) visit(node.thisParameter);
node.parameters.forEach(visit);
visit(node.returnContinuation);
- visit(node.body);
}
// Expressions.
@@ -1184,21 +1179,17 @@
visitLetPrim(LetPrim node) {
processLetPrim(node);
visit(node.primitive);
- visit(node.body);
}
processLetCont(LetCont node) {}
visitLetCont(LetCont node) {
processLetCont(node);
node.continuations.forEach(visit);
- visit(node.body);
}
processLetHandler(LetHandler node) {}
visitLetHandler(LetHandler node) {
processLetHandler(node);
- visit(node.handler);
- visit(node.body);
}
processLetMutable(LetMutable node) {}
@@ -1206,7 +1197,6 @@
processLetMutable(node);
visit(node.variable);
processReference(node.value);
- visit(node.body);
}
processInvokeStatic(InvokeStatic node) {}
@@ -1339,7 +1329,6 @@
visitContinuation(Continuation node) {
processContinuation(node);
node.parameters.forEach(visitParameter);
- if (node.body != null) visit(node.body);
}
processIsTrue(IsTrue node) {}
@@ -1408,12 +1397,6 @@
node.arguments.forEach(processReference);
}
- processNonTailThrow(NonTailThrow node) {}
- visitNonTailThrow(NonTailThrow node) {
- processNonTailThrow(node);
- processReference(node.value);
- }
-
processCreateInvocationMirror(CreateInvocationMirror node) {}
visitCreateInvocationMirror(CreateInvocationMirror node) {
processCreateInvocationMirror(node);
@@ -1462,15 +1445,132 @@
}
}
+typedef void StackAction();
+
+/// Calls `process*` for all nodes in a tree.
+/// For simple usage, only override the `process*` methods.
+///
+/// To avoid deep recursion, this class uses an "action stack" containing
+/// callbacks to be invoked after the processing of some term has finished.
+///
+/// To avoid excessive overhead from the action stack, basic blocks of
+/// interior nodes are iterated in a loop without using the action stack.
+///
+/// The iteration order can be controlled by overriding the `traverse*`
+/// methods for [LetCont], [LetPrim], [LetMutable], [LetHandler] and
+/// [Continuation].
+///
+/// The `traverse*` methods return the expression to visit next, and may
+/// push other subterms onto the stack using [push] or [pushAction] to visit
+/// them later. Actions pushed onto the stack will be executed after the body
+/// has been processed (and the stack actions it pushed have been executed).
+///
+/// By default, the `traverse` methods visit all non-recursive subterms,
+/// push all bound continuations on the stack, and return the body of the term.
+///
+/// Subclasses should not override the `visit` methods for the nodes that have
+/// a `traverse` method.
+class RecursiveVisitor extends LeafVisitor {
+ List<StackAction> _stack = <StackAction>[];
+
+ void pushAction(StackAction callback) {
+ _stack.add(callback);
+ }
+
+ void push(Continuation cont) {
+ _stack.add(() {
+ if (cont.isReturnContinuation) {
+ traverseContinuation(cont);
+ } else {
+ _processBlock(traverseContinuation(cont));
+ }
+ });
+ }
+
+ visitFunctionDefinition(FunctionDefinition node) {
+ processFunctionDefinition(node);
+ if (node.thisParameter != null) visit(node.thisParameter);
+ node.parameters.forEach(visit);
+ visit(node.returnContinuation);
+ visit(node.body);
+ }
+
+ visitContinuation(Continuation cont) {
+ if (cont.isReturnContinuation) {
+ traverseContinuation(cont);
+ } else {
+ _trampoline(traverseContinuation(cont));
+ }
+ }
+
+ visitLetPrim(LetPrim node) => _trampoline(node);
+ visitLetCont(LetCont node) => _trampoline(node);
+ visitLetHandler(LetHandler node) => _trampoline(node);
+ visitLetMutable(LetMutable node) => _trampoline(node);
+
+ Expression traverseContinuation(Continuation cont) {
+ processContinuation(cont);
+ cont.parameters.forEach(visitParameter);
+ return cont.body;
+ }
+
+ Expression traverseLetCont(LetCont node) {
+ processLetCont(node);
+ node.continuations.forEach(push);
+ return node.body;
+ }
+
+ Expression traverseLetHandler(LetHandler node) {
+ processLetHandler(node);
+ push(node.handler);
+ return node.body;
+ }
+
+ Expression traverseLetPrim(LetPrim node) {
+ processLetPrim(node);
+ visit(node.primitive);
+ return node.body;
+ }
+
+ Expression traverseLetMutable(LetMutable node) {
+ processLetMutable(node);
+ visit(node.variable);
+ processReference(node.value);
+ return node.body;
+ }
+
+ void _trampoline(Expression node) {
+ int initialHeight = _stack.length;
+ _processBlock(node);
+ while (_stack.length > initialHeight) {
+ StackAction callback = _stack.removeLast();
+ callback();
+ }
+ }
+
+ _processBlock(Expression node) {
+ while (node is InteriorExpression) {
+ if (node is LetCont) {
+ node = traverseLetCont(node);
+ } else if (node is LetHandler) {
+ node = traverseLetHandler(node);
+ } else if (node is LetPrim) {
+ node = traverseLetPrim(node);
+ } else {
+ node = traverseLetMutable(node);
+ }
+ }
+ visit(node);
+ }
+}
+
/// Visit a just-deleted subterm and unlink all [Reference]s in it.
class RemovalVisitor extends RecursiveVisitor {
- const RemovalVisitor();
-
processReference(Reference reference) {
reference.unlink();
}
static void remove(Node node) {
- (const RemovalVisitor()).visit(node);
+ (new RemovalVisitor()).visit(node);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index c6cdfc5..1a317c4 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -314,11 +314,6 @@
return '(TypeExpression ${node.dartType} ($args))';
}
- String visitNonTailThrow(NonTailThrow node) {
- String value = access(node.value);
- return '(NonTailThrow $value)';
- }
-
String visitCreateInvocationMirror(CreateInvocationMirror node) {
String selector = node.selector.name;
String args = node.arguments.map(access).join(' ');
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index a299237..ba67e95 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -339,11 +339,6 @@
"${node.arguments.map(formatReference).join(', ')}";
}
- visitNonTailThrow(cps_ir.NonTailThrow node) {
- String value = formatReference(node.value);
- return "NonTailThrow($value)";
- }
-
visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
String args = node.arguments.map(formatReference).join(', ');
return "CreateInvocationMirror(${node.selector.name}, $args)";
@@ -365,8 +360,7 @@
visitForeignCode(cps_ir.ForeignCode node) {
String id = names.name(node);
String arguments = node.arguments.map(formatReference).join(', ');
- String continuation = node.continuation == null ? ''
- : ' ${formatReference(node.continuation)}';
+ String continuation = formatReference(node.continuation);
printStmt(id, "ForeignCode ${node.type} ${node.codeTemplate.source} "
"$arguments $continuation");
}
@@ -619,10 +613,6 @@
unexpectedNode(node);
}
- visitNonTailThrow(cps_ir.NonTailThrow node) {
- unexpectedNode(node);
- }
-
visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
unexpectedNode(node);
}
@@ -661,8 +651,6 @@
@override
visitForeignCode(cps_ir.ForeignCode node) {
- if (node.continuation != null) {
- addEdgeToContinuation(node.continuation);
- }
+ addEdgeToContinuation(node.continuation);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/let_sinking.dart b/pkg/compiler/lib/src/cps_ir/let_sinking.dart
index c7f2c21..4c4736a 100644
--- a/pkg/compiler/lib/src/cps_ir/let_sinking.dart
+++ b/pkg/compiler/lib/src/cps_ir/let_sinking.dart
@@ -8,29 +8,34 @@
import 'optimizers.dart';
/// Sinks single-use primitives to the use when this is safe and profitable.
-///
+///
/// To avoid sinking non-constant primitives into loops, this pass performs a
/// control-flow analysis to determine the effective nesting of loops.
-///
-/// In the example below, the value 'p' can be sunk to its use site in the
+///
+/// In the example below, the value 'p' can be sunk to its use site in the
/// 'else' branch because that branch is not effectively part of a loop,
/// despite being lexically nested in a recursive continuation.
-///
+///
/// let prim p = getInterceptor(<something>)
-/// let rec kont x =
-/// if (<loop condition>)
+/// let rec kont x =
+/// if (<loop condition>)
/// <loop body>
/// InvokeContinuation kont x'
-/// else
+/// else
/// <after loop>
/// return p.foo()
-///
+///
class LetSinker extends RecursiveVisitor implements Pass {
String get passName => 'Let sinking';
LoopHierarchy loopHierarchy;
List<Continuation> stack = <Continuation>[];
- Set<LetPrim> sunkNodes = new Set<LetPrim>();
+
+ /// Maps a sinkable primitive to its loop header.
+ Map<Primitive, Continuation> loopHeaderForPrimitive =
+ <Primitive, Continuation>{};
+
+ Continuation currentLoopHeader;
void rewrite(FunctionDefinition node) {
new ParentVisitor().visit(node);
@@ -38,19 +43,40 @@
visit(node.body);
}
- void visitLetPrim(LetPrim node) {
- // Visit the body, wherein this primitive may be sunk to its use site.
- visit(node.body);
-
- if (node.primitive != null) {
- // The primitive could not be sunk. Sink dependencies to this location.
- visit(node.primitive);
+ @override
+ Expression traverseLetPrim(LetPrim node) {
+ Primitive prim = node.primitive;
+ if (prim.hasExactlyOneUse && prim.isSafeForReordering) {
+ // This can potentially be sunk. Register the loop header, so when we
+ // find the use site, we can check if they are in the same loop.
+ loopHeaderForPrimitive[prim] = currentLoopHeader;
+ pushAction(() {
+ if (node.primitive != null) {
+ // The primitive could not be sunk. Try to sink dependencies here.
+ visit(node.primitive);
+ } else {
+ // The primitive was sunk. Destroy the old LetPrim.
+ InteriorNode parent = node.parent;
+ parent.body = node.body;
+ node.body.parent = parent;
+ }
+ });
} else {
- // The primitive was sunk. Destroy the old LetPrim.
- InteriorNode parent = node.parent;
- parent.body = node.body;
- node.body.parent = parent;
+ visit(node.primitive);
}
+
+ // Visit the body, wherein this primitive may be sunk to its use site.
+ return node.body;
+ }
+
+ @override
+ Expression traverseContinuation(Continuation cont) {
+ Continuation oldLoopHeader = currentLoopHeader;
+ pushAction(() {
+ currentLoopHeader = oldLoopHeader;
+ });
+ currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+ return cont.body;
}
void processReference(Reference ref) {
@@ -60,13 +86,12 @@
definition.hasExactlyOneUse &&
definition.isSafeForReordering) {
// Check if use is in the same loop.
- LetPrim binding = definition.parent;
- Continuation bindingLoop = loopHierarchy.getLoopHeader(binding);
- Expression use = getEnclosingExpression(ref.parent);
- Continuation useLoop = loopHierarchy.getLoopHeader(use);
- if (bindingLoop == useLoop || definition is Constant) {
+ Continuation bindingLoop = loopHeaderForPrimitive.remove(definition);
+ if (bindingLoop == currentLoopHeader || definition is Constant) {
// Sink the definition.
+ Expression use = getEnclosingExpression(ref.parent);
+ LetPrim binding = definition.parent;
binding.primitive = null; // Mark old binding for deletion.
LetPrim newBinding = new LetPrim(definition);
definition.parent = newBinding;
@@ -127,20 +152,9 @@
_processBlock(node.body, null);
}
- /// Returns the innermost loop which [node] is effectively part of.
- Continuation getLoopHeader(Expression exp) {
- Node node = exp.parent;
- while (node != null && node is! Continuation) {
- node = node.parent;
- }
- if (node is Continuation) {
- if (node.isRecursive) {
- return node;
- } else {
- return loopTarget[node];
- }
- }
- return null;
+ /// Returns the innermost loop which [cont] is effectively part of.
+ Continuation getLoopHeader(Continuation cont) {
+ return cont.isRecursive ? cont : loopTarget[cont];
}
/// Marks the innermost loop as a subloop of the other loop.
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
index c561e81..d01c3f5 100644
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
@@ -26,11 +26,12 @@
/// its declaration.
Set<MutableVariable> hasAssignmentInTry = new Set<MutableVariable>();
- void visitLetHandler(LetHandler node) {
+ @override
+ Expression traverseLetHandler(LetHandler node) {
+ push(node.handler);
++currentDepth;
- visit(node.body);
- --currentDepth;
- visit(node.handler);
+ pushAction(() => --currentDepth);
+ return node.body;
}
void processLetMutable(LetMutable node) {
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index 92bd51b..2a1a584 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -234,7 +234,7 @@
class AlphaRenamer extends RecursiveVisitor {
Map<Parameter, Parameter> renaming = <Parameter, Parameter>{};
- visitContinuation(Continuation cont) {
+ processContinuation(Continuation cont) {
if (cont.isReturnContinuation) return;
List<Parameter> shadowedKeys = <Parameter>[];
@@ -255,16 +255,15 @@
}
}
- // Visit the body with the updated environment.
- visit(cont.body);
-
- // Restore the original environment.
- for (int i = 0; i < cont.parameters.length; ++i) {
- renaming.remove(cont.parameters[i]);
- if (shadowedValues[i] != null) {
- renaming[shadowedKeys[i]] = shadowedValues[i];
+ pushAction(() {
+ // Restore the original environment.
+ for (int i = 0; i < cont.parameters.length; ++i) {
+ renaming.remove(cont.parameters[i]);
+ if (shadowedValues[i] != null) {
+ renaming[shadowedKeys[i]] = shadowedValues[i];
+ }
}
- }
+ });
}
processReference(Reference ref) {
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index 0173804..ac1d143 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -14,14 +14,14 @@
class ShrinkingReducer extends Pass {
String get passName => 'Shrinking reductions';
- Set<_ReductionTask> _worklist;
+ List<_ReductionTask> _worklist;
static final _DeletedNode _DELETED = new _DeletedNode();
/// Applies shrinking reductions to root, mutating root in the process.
@override
void rewrite(FunctionDefinition root) {
- _worklist = new Set<_ReductionTask>();
+ _worklist = new List<_ReductionTask>();
_RedexVisitor redexVisitor = new _RedexVisitor(_worklist);
// Set all parent pointers.
@@ -32,8 +32,7 @@
// Process the worklist.
while (_worklist.isNotEmpty) {
- _ReductionTask task = _worklist.first;
- _worklist.remove(task);
+ _ReductionTask task = _worklist.removeLast();
_processTask(task);
}
}
@@ -400,7 +399,7 @@
/// Traverses a term and adds any found redexes to the worklist.
class _RedexVisitor extends RecursiveVisitor {
- final Set<_ReductionTask> worklist;
+ final List<_ReductionTask> worklist;
_RedexVisitor(this.worklist);
@@ -446,7 +445,7 @@
/// any corresponding tasks can be skipped. Nodes are marked so by setting
/// their parent to the deleted sentinel.
class _RemovalVisitor extends RecursiveVisitor {
- final Set<_ReductionTask> worklist;
+ final List<_ReductionTask> worklist;
_RemovalVisitor(this.worklist);
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 60e9c4c..5784bba 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -546,7 +546,7 @@
* Uses the information from a preceding analysis pass in order to perform the
* actual transformations on the CPS graph.
*/
-class TransformingVisitor extends RecursiveVisitor {
+class TransformingVisitor extends LeafVisitor {
final TypePropagationVisitor analyzer;
final Map<Expression, ConstantValue> replacements;
final ConstantPropagationLattice lattice;
@@ -555,11 +555,12 @@
JavaScriptBackend get backend => compiler.backend;
TypeMaskSystem get typeSystem => lattice.typeSystem;
types.DartTypes get dartTypes => lattice.dartTypes;
- Set<Node> get reachable => analyzer.reachableNodes;
Map<Node, AbstractValue> get values => analyzer.values;
final dart2js.InternalErrorFunction internalError;
+ final List<Node> stack = <Node>[];
+
TransformingVisitor(this.compiler,
this.lattice,
this.analyzer,
@@ -567,9 +568,81 @@
this.internalError);
void transform(FunctionDefinition root) {
- visit(root);
+ push(root.body);
+ while (stack.isNotEmpty) {
+ visit(stack.removeLast());
+ }
}
+ void push(Node node) {
+ assert(node != null);
+ stack.add(node);
+ }
+
+ void pushAll(Iterable<Node> nodes) {
+ nodes.forEach(push);
+ }
+
+ /************************* INTERIOR EXPRESSIONS *************************/
+ //
+ // These return nothing, and must push recursive children on the stack.
+
+ void visitLetCont(LetCont node) {
+ pushAll(node.continuations);
+ push(node.body);
+ }
+
+ void visitLetHandler(LetHandler node) {
+ push(node.handler);
+ push(node.body);
+ }
+
+ void visitLetMutable(LetMutable node) {
+ visit(node.variable);
+ push(node.body);
+ }
+
+ void visitLetPrim(LetPrim node) {
+ AbstractValue value = getValue(node.primitive);
+ if (node.primitive is! Constant && value.isConstant) {
+ // If the value is a known constant, compile it as a constant.
+ Constant newPrim = makeConstantPrimitive(value.constant);
+ newPrim.substituteFor(node.primitive);
+ RemovalVisitor.remove(node.primitive);
+ node.primitive = newPrim;
+ newPrim.parent = node;
+ } else {
+ Primitive newPrim = visit(node.primitive);
+ if (newPrim != null) {
+ newPrim.substituteFor(node.primitive);
+ RemovalVisitor.remove(node.primitive);
+ node.primitive = newPrim;
+ newPrim.parent = node;
+ reanalyze(newPrim);
+ }
+ if (node.primitive.hasNoUses && node.primitive.isSafeForElimination) {
+ // Remove unused primitives before entering the body.
+ // This would also be done by shrinking reductions, but usage analyses
+ // such as isAlwaysBoolified are more precise without the dead uses, so
+ // we prefer to remove them early.
+ RemovalVisitor.remove(node.primitive);
+ node.parent.body = node.body;
+ node.body.parent = node.parent;
+ }
+ }
+ push(node.body);
+ }
+
+ void visitContinuation(Continuation node) {
+ if (node.isReturnContinuation) return;
+ // Process the continuation body.
+ // Note that the continuation body may have changed since the continuation
+ // was put on the stack (e.g. [visitInvokeContinuation] may do this).
+ push(node.body);
+ }
+
+ /************************* TRANSFORMATION HELPERS *************************/
+
/// Sets parent pointers and computes types for the given subtree.
void reanalyze(Node node) {
new ParentVisitor().visit(node);
@@ -623,6 +696,16 @@
context.body = node;
node.parent = context;
}
+
+ /// Binds [prim] before [node].
+ void insertLetPrim(Expression node, Primitive prim) {
+ InteriorNode parent = node.parent;
+ LetPrim let = new LetPrim(prim);
+ parent.body = let;
+ let.body = node;
+ node.parent = let;
+ let.parent = parent;
+ }
/// Make a constant primitive for [constant] and set its entry in [values].
Constant makeConstantPrimitive(ConstantValue constant) {
@@ -648,23 +731,7 @@
return letPrim;
}
- /// Side-effect free expressions with constant results are be replaced by:
- ///
- /// (LetPrim p = constant (InvokeContinuation k p)).
- ///
- /// The new expression will be visited.
- ///
- /// Returns true if the node was replaced.
- bool constifyExpression(CallExpression node) {
- Continuation continuation = node.continuation.definition;
- ConstantValue constant = replacements[node];
- if (constant == null) return false;
- Constant primitive = makeConstantPrimitive(constant);
- LetPrim letPrim = makeLetPrimInvoke(primitive, continuation);
- replaceSubtree(node, letPrim);
- visitLetPrim(letPrim);
- return true;
- }
+ /************************* TAIL EXPRESSIONS *************************/
// A branch can be eliminated and replaced by an invocation if only one of
// the possible continuations is reachable. Removal often leads to both dead
@@ -684,13 +751,13 @@
if (boolifiedValue == AbstractBool.True) {
InvokeContinuation invoke = new InvokeContinuation(trueCont, []);
replaceSubtree(node, invoke);
- visitInvokeContinuation(invoke);
+ push(invoke);
return;
}
if (boolifiedValue == AbstractBool.False) {
InvokeContinuation invoke = new InvokeContinuation(falseCont, []);
replaceSubtree(node, invoke);
- visitInvokeContinuation(invoke);
+ push(invoke);
return;
}
@@ -718,6 +785,36 @@
}
}
+ void visitInvokeContinuation(InvokeContinuation node) {
+ // Inline the single-use continuations. These are often introduced when
+ // specializing an invocation node. These would also be inlined by a later
+ // pass, but doing it here helps simplify pattern matching code, since the
+ // effective definition of a primitive can then be found without going
+ // through redundant InvokeContinuations.
+ Continuation cont = node.continuation.definition;
+ if (cont.hasExactlyOneUse &&
+ !cont.isReturnContinuation &&
+ !cont.isRecursive &&
+ !node.isEscapingTry) {
+ for (int i = 0; i < node.arguments.length; ++i) {
+ node.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
+ node.arguments[i].definition.substituteFor(cont.parameters[i]);
+ node.arguments[i].unlink();
+ }
+ node.continuation.unlink();
+ InteriorNode parent = node.parent;
+ Expression body = cont.body;
+ parent.body = body;
+ body.parent = parent;
+ cont.body = new Unreachable();
+ cont.body.parent = cont;
+ push(body);
+ }
+ }
+
+
+ /************************* CALL EXPRESSIONS *************************/
+
/// Replaces [node] with a more specialized instruction, if possible.
///
/// Returns `true` if the node was replaced.
@@ -727,10 +824,11 @@
Primitive left,
Primitive right) {
Primitive prim =
- new ApplyBuiltinOperator(operator, <Primitive>[left, right]);
+ new ApplyBuiltinOperator(operator, <Primitive>[left, right],
+ node.sourceInformation);
LetPrim let = makeLetPrimInvoke(prim, cont);
replaceSubtree(node, let);
- visitLetPrim(let);
+ push(let);
return true; // So returning early is more convenient.
}
@@ -828,7 +926,7 @@
GetField get = new GetField(getDartReceiver(node), target);
LetPrim let = makeLetPrimInvoke(get, cont);
replaceSubtree(node, let);
- visitLetPrim(let);
+ push(let);
return true;
} else {
if (target.isFinal) return false;
@@ -840,7 +938,7 @@
getDartArgument(node, 0)));
cps.invokeContinuation(cont);
replaceSubtree(node, cps.result);
- visit(cps.result);
+ push(cps.result);
return true;
}
}
@@ -933,7 +1031,7 @@
CpsFragment cps = new CpsFragment(sourceInfo);
cps.invokeContinuation(cont, [cps.letPrim(new GetLength(list))]);
replaceSubtree(node, cps.result);
- visit(cps.result);
+ push(cps.result);
return true;
case '[]':
@@ -945,7 +1043,7 @@
GetIndex get = cps.letPrim(new GetIndex(list, index));
cps.invokeContinuation(cont, [get]);
replaceSubtree(node, cps.result);
- visit(cps.result);
+ push(cps.result);
return true;
case '[]=':
@@ -961,7 +1059,7 @@
cont.parameters.clear();
cps.invokeContinuation(cont, []);
replaceSubtree(node, cps.result);
- visit(cps.result);
+ push(cps.result);
return true;
case 'forEach':
@@ -1014,7 +1112,7 @@
cps.continueLoop(loop, [addOne]);
replaceSubtree(node, cps.result);
- visit(cps.result);
+ push(cps.result);
return true;
case 'iterator':
@@ -1165,9 +1263,7 @@
insertBefore(iteratorCont.body, cps);
InvokeContinuation invoke = new InvokeContinuation(iteratorCont, []);
replaceSubtree(node, invoke);
- visit(invoke);
- // TODO(asgerf): A procedure for rewriting mutables into parameters
- // might enable further optimizations after this.
+ push(invoke);
return true;
// TODO(asgerf): Rewrite 'add', 'removeLast', ...
@@ -1242,7 +1338,7 @@
node.sourceInformation);
node.receiver.unlink();
replaceSubtree(node, invoke, unlink: false);
- visitInvokeStatic(invoke);
+ push(invoke);
return true;
}
CallExpression tearOffInvoke = getCallWithResult(tearOff);
@@ -1300,12 +1396,30 @@
assert(isPure);
}
- visitInvokeMethod(invoke);
+ push(invoke);
return true;
}
return false;
}
+ /// Side-effect free expressions with constant results are be replaced by:
+ ///
+ /// (LetPrim p = constant (InvokeContinuation k p)).
+ ///
+ /// The new expression will be visited.
+ ///
+ /// Returns true if the node was replaced.
+ bool constifyExpression(CallExpression node) {
+ Continuation continuation = node.continuation.definition;
+ ConstantValue constant = replacements[node];
+ if (constant == null) return false;
+ Constant primitive = makeConstantPrimitive(constant);
+ LetPrim letPrim = makeLetPrimInvoke(primitive, continuation);
+ replaceSubtree(node, letPrim);
+ push(letPrim);
+ return true;
+ }
+
void visitInvokeMethod(InvokeMethod node) {
if (constifyExpression(node)) return;
if (specializeOperatorCall(node)) return;
@@ -1315,7 +1429,6 @@
AbstractValue receiver = getValue(node.receiver.definition);
node.receiverIsNotNull = receiver.isDefinitelyNotNull;
- super.visitInvokeMethod(node);
}
void visitTypeCast(TypeCast node) {
@@ -1332,17 +1445,14 @@
InvokeContinuation invoke =
new InvokeContinuation(cont, <Primitive>[node.value.definition]);
replaceSubtree(node, invoke);
- visitInvokeContinuation(invoke);
+ push(invoke);
return;
case AbstractBool.False:
// Cast always fails, remove unreachable continuation body.
- assert(!reachable.contains(cont));
replaceSubtree(cont.body, new Unreachable());
break;
}
-
- super.visitTypeCast(node);
}
/// Specialize calls to internal static methods.
@@ -1361,7 +1471,7 @@
InvokeContinuation invoke =
new InvokeContinuation(cont, <Primitive>[arg(0)]);
replaceSubtree(node, invoke);
- visitInvokeContinuation(invoke);
+ push(invoke);
return true;
}
break;
@@ -1380,14 +1490,13 @@
return value == null ? new AbstractValue.nothing() : value;
}
- void insertLetPrim(Expression node, Primitive prim) {
- InteriorNode parent = node.parent;
- LetPrim let = new LetPrim(prim);
- parent.body = let;
- let.body = node;
- node.parent = let;
- let.parent = parent;
- }
+
+ /*************************** PRIMITIVES **************************/
+ //
+ // The visit method for a primitive may optionally return a new
+ // primitive. If non-null, the surrounding LetPrim will substitute it
+ // and bind the new primitive instead.
+ //
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
DartString getString(AbstractValue value) {
@@ -1461,18 +1570,21 @@
// If value is null or a number, we can skip the typeof test.
return new ApplyBuiltinOperator(
BuiltinOperator.IsFloor,
- <Primitive>[prim, prim]);
+ <Primitive>[prim, prim],
+ node.sourceInformation);
}
if (lattice.isDefinitelyNotNonIntegerDouble(value)) {
// If the value cannot be a non-integer double, but might not be a
// number at all, we can skip the Math.floor test.
return new ApplyBuiltinOperator(
BuiltinOperator.IsNumber,
- <Primitive>[prim]);
+ <Primitive>[prim],
+ node.sourceInformation);
}
return new ApplyBuiltinOperator(
BuiltinOperator.IsNumberAndFloor,
- <Primitive>[prim, prim, prim]);
+ <Primitive>[prim, prim, prim],
+ node.sourceInformation);
}
return null;
}
@@ -1485,73 +1597,6 @@
node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
}
- void visitLetPrim(LetPrim node) {
- AbstractValue value = getValue(node.primitive);
- if (node.primitive is! Constant && value.isConstant) {
- // If the value is a known constant, compile it as a constant.
- Constant newPrim = makeConstantPrimitive(value.constant);
- newPrim.substituteFor(node.primitive);
- RemovalVisitor.remove(node.primitive);
- node.primitive = newPrim;
- newPrim.parent = node;
- } else {
- Primitive newPrim = visit(node.primitive);
- if (newPrim != null) {
- newPrim.substituteFor(node.primitive);
- RemovalVisitor.remove(node.primitive);
- node.primitive = newPrim;
- newPrim.parent = node;
- reanalyze(newPrim);
- }
- if (node.primitive.hasNoUses && node.primitive.isSafeForElimination) {
- // Remove unused primitives before entering the body.
- // This would also be done by shrinking reductions, but usage analyses
- // such as isAlwaysBoolified are more precise without the dead uses, so
- // we prefer to remove them early.
- RemovalVisitor.remove(node.primitive);
- node.parent.body = node.body;
- node.body.parent = node.parent;
- }
- }
- visit(node.body);
- }
-
- void visitLetCont(LetCont node) {
- // Visit body before continuations to ensure more information is available
- // about the parameters. In particular, if this is a call continuation, its
- // invocation should be specialized before the body is processed, because
- // we specialize definitions before their uses.
- visit(node.body);
- node.continuations.forEach(visit);
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- // Inline the single-use continuations. These are often introduced when
- // specializing an invocation node. These would also be inlined by a later
- // pass, but doing it here helps simplify pattern matching code, since the
- // effective definition of a primitive can then be found without going
- // through redundant InvokeContinuations.
- Continuation cont = node.continuation.definition;
- if (cont.hasExactlyOneUse &&
- !cont.isReturnContinuation &&
- !cont.isRecursive &&
- !node.isEscapingTry) {
- for (int i = 0; i < node.arguments.length; ++i) {
- node.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
- node.arguments[i].definition.substituteFor(cont.parameters[i]);
- node.arguments[i].unlink();
- }
- node.continuation.unlink();
- InteriorNode parent = node.parent;
- Expression body = cont.body;
- parent.body = body;
- body.parent = parent;
- cont.body = new Unreachable();
- cont.body.parent = cont;
- visit(body);
- }
- }
-
void visitInterceptor(Interceptor node) {
// Filter out intercepted classes that do not match the input type.
AbstractValue value = getValue(node.input.definition);
@@ -1586,11 +1631,11 @@
// TODO(jgruber): Storing reachability per-edge instead of per-node would
// allow for further optimizations.
final List<Node> nodeWorklist = <Node>[];
- final Set<Node> reachableNodes = new Set<Node>();
+ final Set<Continuation> reachableContinuations = new Set<Continuation>();
// The definition workset stores all definitions which need to be reprocessed
// since their lattice value has changed.
- final Set<Definition> defWorkset = new Set<Definition>();
+ final List<Definition> defWorklist = <Definition>[];
final ConstantPropagationLattice lattice;
final dart2js.InternalErrorFunction internalError;
@@ -1619,17 +1664,17 @@
this.internalError);
void analyze(FunctionDefinition root) {
- reachableNodes.clear();
+ reachableContinuations.clear();
// Initially, only the root node is reachable.
- setReachable(root);
+ push(root);
iterateWorklist();
}
void reanalyzeSubtree(Node node) {
- new ResetAnalysisInfo(reachableNodes, values).visit(node);
- setReachable(node);
+ new ResetAnalysisInfo(reachableContinuations, values).visit(node);
+ push(node);
iterateWorklist();
}
@@ -1639,10 +1684,9 @@
// Process a new reachable expression.
Node node = nodeWorklist.removeLast();
visit(node);
- } else if (defWorkset.isNotEmpty) {
+ } else if (defWorklist.isNotEmpty) {
// Process all usages of a changed definition.
- Definition def = defWorkset.first;
- defWorkset.remove(def);
+ Definition def = defWorklist.removeLast();
// Visit all uses of this definition. This might add new entries to
// [nodeWorklist], for example by visiting a newly-constant usage within
@@ -1656,19 +1700,23 @@
}
}
+ /// Adds [node] to the worklist.
+ void push(Node node) {
+ nodeWorklist.add(node);
+ }
+
/// If the passed node is not yet reachable, mark it reachable and add it
/// to the work list.
- void setReachable(Node node) {
- if (!reachableNodes.contains(node)) {
- reachableNodes.add(node);
- nodeWorklist.add(node);
+ void setReachable(Continuation cont) {
+ if (reachableContinuations.add(cont)) {
+ push(cont);
}
}
/// Returns the lattice value corresponding to [node], defaulting to nothing.
///
/// Never returns null.
- AbstractValue getValue(Node node) {
+ AbstractValue getValue(Definition node) {
AbstractValue value = values[node];
return (value == null) ? nothing : value;
}
@@ -1676,7 +1724,7 @@
/// Joins the passed lattice [updateValue] to the current value of [node],
/// and adds it to the definition work set if it has changed and [node] is
/// a definition.
- void setValue(Node node, AbstractValue updateValue) {
+ void setValue(Definition node, AbstractValue updateValue) {
AbstractValue oldValue = getValue(node);
AbstractValue newValue = lattice.join(oldValue, updateValue);
if (oldValue == newValue) {
@@ -1687,9 +1735,7 @@
assert(newValue.kind >= oldValue.kind);
values[node] = newValue;
- if (node is Definition) {
- defWorkset.add(node);
- }
+ defWorklist.add(node);
}
// -------------------------- Visitor overrides ------------------------------
@@ -1701,21 +1747,21 @@
nonConstant(typeSystem.getReceiverType(node.element)));
}
node.parameters.forEach(visit);
- setReachable(node.body);
+ push(node.body);
}
void visitLetPrim(LetPrim node) {
visit(node.primitive); // No reason to delay visits to primitives.
- setReachable(node.body);
+ push(node.body);
}
void visitLetCont(LetCont node) {
// The continuation is only marked as reachable on use.
- setReachable(node.body);
+ push(node.body);
}
void visitLetHandler(LetHandler node) {
- setReachable(node.body);
+ push(node.body);
// The handler is assumed to be reachable (we could instead treat it as
// unreachable unless we find something reachable that might throw in the
// body --- it's not clear if we want to do that here or in some other
@@ -1732,7 +1778,7 @@
void visitLetMutable(LetMutable node) {
setValue(node.variable, getValue(node.value.definition));
- setReachable(node.body);
+ push(node.body);
}
void visitInvokeStatic(InvokeStatic node) {
@@ -1954,10 +2000,6 @@
void visitUnreachable(Unreachable node) {
}
- void visitNonTailThrow(NonTailThrow node) {
- internalError(null, 'found non-tail throw after they were eliminated');
- }
-
void visitBranch(Branch node) {
IsTrue isTrue = node.condition;
AbstractValue conditionCell = getValue(isTrue.value.definition);
@@ -2052,10 +2094,7 @@
}
void visitCreateFunction(CreateFunction node) {
- setReachable(node.definition);
- ConstantValue constant =
- new FunctionConstantValue(node.definition.element);
- setValue(node, constantValue(constant, typeSystem.functionType));
+ throw 'CreateFunction is not used';
}
void visitGetMutable(GetMutable node) {
@@ -2102,7 +2141,7 @@
node.parameters.forEach(visit);
if (node.body != null) {
- setReachable(node.body);
+ push(node.body);
}
}
@@ -2131,7 +2170,7 @@
}
void visitInterceptor(Interceptor node) {
- setReachable(node.input.definition);
+ push(node.input.definition);
AbstractValue value = getValue(node.input.definition);
if (!value.isNothing) {
setValue(node, nonConstant(typeSystem.nonNullType));
@@ -2294,14 +2333,21 @@
}
class ResetAnalysisInfo extends RecursiveVisitor {
- Set<Node> reachableNodes;
+ Set<Continuation> reachableContinuations;
Map<Definition, AbstractValue> values;
- ResetAnalysisInfo(this.reachableNodes, this.values);
+ ResetAnalysisInfo(this.reachableContinuations, this.values);
- visit(Node node) {
- reachableNodes.remove(node);
- if (node is Definition) values.remove(node);
- node.accept(this);
+ processContinuation(Continuation cont) {
+ reachableContinuations.remove(cont);
+ cont.parameters.forEach(values.remove);
+ }
+
+ processLetPrim(LetPrim node) {
+ values.remove(node.primitive);
+ }
+
+ processLetMutable(LetMutable node) {
+ values.remove(node.variable);
}
}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 5e36769..24a058f 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -503,7 +503,7 @@
void fail(String message) {
if (diagnosticHandler != null) {
diagnosticHandler.report(
- null, -1, -1, message, api.Diagnostic.ERROR);
+ null, null, -1, -1, message, api.Diagnostic.ERROR);
} else {
print('Error: $message');
}
diff --git a/pkg/compiler/lib/src/dart2jslib.dart b/pkg/compiler/lib/src/dart2jslib.dart
index 14dad6a..e5c924d 100644
--- a/pkg/compiler/lib/src/dart2jslib.dart
+++ b/pkg/compiler/lib/src/dart2jslib.dart
@@ -60,9 +60,11 @@
import 'tree/tree.dart';
import 'types/types.dart' as ti;
import 'universe/universe.dart';
+import 'universe/class_set.dart';
import 'util/characters.dart' show $_;
import 'util/uri_extras.dart' as uri_extras show relativize;
import 'util/util.dart';
+import 'warnings.dart';
export 'helpers/helpers.dart';
export 'resolution/resolution.dart' show TreeElements, TreeElementMapping;
@@ -76,6 +78,7 @@
show Spannable,
CURRENT_ELEMENT_SPANNABLE,
NO_LOCATION_SPANNABLE;
+export 'warnings.dart';
part 'compiler.dart';
part 'diagnostic_listener.dart';
@@ -83,5 +86,4 @@
part 'resolved_visitor.dart';
part 'script.dart';
part 'typechecker.dart';
-part 'warnings.dart';
part 'world.dart';
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index e261ff6..3ae1bae 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -252,6 +252,30 @@
Set<ConstantValue> constants,
isMirrorUsage) {
+ /// Recursively collects all the dependencies of [type].
+ void collectTypeDependencies(DartType type) {
+ if (type is GenericType) {
+ type.typeArguments.forEach(collectTypeDependencies);
+ }
+ if (type is FunctionType) {
+ for (DartType argumentType in type.parameterTypes) {
+ collectTypeDependencies(argumentType);
+ }
+ for (DartType argumentType in type.optionalParameterTypes) {
+ collectTypeDependencies(argumentType);
+ }
+ for (DartType argumentType in type.namedParameterTypes) {
+ collectTypeDependencies(argumentType);
+ }
+ collectTypeDependencies(type.returnType);
+ } else if (type is TypedefType) {
+ elements.add(type.element);
+ collectTypeDependencies(type.unalias(compiler));
+ } else if (type is InterfaceType) {
+ elements.add(type.element);
+ }
+ }
+
/// Collects all direct dependencies of [element].
///
/// The collected dependent elements and constants are are added to
@@ -281,22 +305,10 @@
elements.add(dependency);
}
- void registerTypeArgumentsAsDependencies(DartType type) {
- Element dependency = type.element;
- if (dependency == null || dependency.isErroneous ||
- dependency.isTypeVariable) {
- return;
- }
- elements.add(dependency);
- if (type is GenericType) {
- type.typeArguments.forEach(registerTypeArgumentsAsDependencies);
- }
+ for (DartType type in treeElements.requiredTypes) {
+ collectTypeDependencies(type);
}
- treeElements.forEachType((Node node, DartType type) {
- if (node is NewExpression) registerTypeArgumentsAsDependencies(type);
- });
-
treeElements.forEachConstantNode((Node node, _) {
// Explicitly depend on the backend constants.
ConstantValue value =
@@ -319,34 +331,11 @@
}
}
- collectTypeDependencies(DartType type) {
- if (type is FunctionType) {
- for (DartType argumentType in type.parameterTypes) {
- collectTypeDependencies(argumentType);
- }
- for (DartType argumentType in type.optionalParameterTypes) {
- collectTypeDependencies(argumentType);
- }
- for (DartType argumentType in type.namedParameterTypes) {
- collectTypeDependencies(argumentType);
- }
- collectTypeDependencies(type.returnType);
- } else if (type is TypedefType) {
- elements.add(type.element);
- collectTypeDependencies(type.unalias(compiler));
- } else if (type is InterfaceType) {
- elements.add(type.element);
- }
- }
-
if (element is FunctionElement &&
compiler.resolverWorld.closurizedMembers.contains(element)) {
collectTypeDependencies(element.type);
}
- // TODO(sigurdm): Also collect types that are used in is checks and for
- // checked mode.
-
if (element.isClass) {
// If we see a class, add everything its live instance members refer
// to. Static members are not relevant, unless we are processing
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 2524fb1..3b8f8bc 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -639,9 +639,10 @@
encoder.startChunkedConversion(
new StringConversionSink.fromStringSink(buffer));
sink.add(outJson);
- compiler.reportInfo(NO_LOCATION_SPANNABLE,
- const MessageKind(
- "View the dumped .info.json file at "
- "https://dart-lang.github.io/dump-info-visualizer"));
+ compiler.reportInfo(
+ NO_LOCATION_SPANNABLE,
+ MessageKind.GENERIC,
+ {'text': "View the dumped .info.json file at "
+ "https://dart-lang.github.io/dump-info-visualizer"});
}
}
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 85d7579..0f96bdb 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -24,6 +24,7 @@
FunctionType,
InterfaceType,
MessageKind,
+ MessageTemplate,
Script,
Selector,
SourceSpan,
@@ -308,7 +309,10 @@
FunctionElement asFunctionElement() => this;
- String get message => '${messageKind.message(messageArguments)}';
+ String get message {
+ return MessageTemplate.TEMPLATES[messageKind]
+ .message(messageArguments).toString();
+ }
String toString() => '<$name: $message>';
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 416d7ea..56b88d1 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -172,7 +172,24 @@
SourceInformation buildLoop(Node node) => buildBegin(node);
@override
- SourceInformation buildGet(Node node) => buildBegin(node);
+ SourceInformation buildGet(Node node) {
+ Node left = node;
+ Node right = node;
+ Send send = node.asSend();
+ if (send != null) {
+ right = send.selector;
+ }
+ // For a read access like `a.b` the first source locations points to the
+ // left-most part of the access, `a` in the example, and the second source
+ // location points to the 'name' of accessed property, `b` in the
+ // example. The latter is needed when both `a` and `b` are compiled into
+ // JavaScript invocations.
+ return new PositionSourceInformation(
+ new OffsetSourceLocation(
+ sourceFile, left.getBeginToken().charOffset, name),
+ new OffsetSourceLocation(
+ sourceFile, right.getBeginToken().charOffset, name));
+ }
@override
SourceInformation buildCall(Node receiver, Node call) {
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index 09d1ca9..7acf719 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -74,13 +74,13 @@
/// Generate [SourceInformation] for the loop [node].
SourceInformation buildLoop(Node node) => null;
- /// Generate [SourceInformation] for the read access in [node].
+ /// Generate [SourceInformation] for a read access like `a.b` where in
+ /// [receiver] points to the left-most part of the access, `a` in the example,
+ /// and [property] points to the 'name' of accessed property, `b` in the
+ /// example.
SourceInformation buildGet(Node node) => null;
- /// Generate [SourceInformation] for an invocation like `a.b()` where
- /// [receiver] points to the left-most part of the invocation, `a` in the
- /// example, and [call] points the 'name' of the call, `b` or `()` depending
- /// on whether `b` is a method or a field/getter.
+ /// Generate [SourceInformation] for the read access in [node].
SourceInformation buildCall(Node receiver, Node call) => null;
/// Generate [SourceInformation] for the if statement in [node].
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index 4547fca..68469eb 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -9,6 +9,7 @@
import '../dart2jslib.dart' show
MessageKind,
+ MessageTemplate,
SourceSpan;
import '../elements/elements.dart' show
AstElement,
@@ -182,10 +183,11 @@
void checkValidSourceFileLocation(
SourceLocation location, SourceFile sourceFile, int offset) {
if (!location.isValid) {
- throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message(
- {'offset': offset,
- 'fileName': sourceFile.filename,
- 'length': sourceFile.length});
+ throw MessageTemplate.TEMPLATES[MessageKind.INVALID_SOURCE_FILE_LOCATION]
+ .message(
+ {'offset': offset,
+ 'fileName': sourceFile.filename,
+ 'length': sourceFile.length});
}
}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index ba39217..91c4765 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -242,10 +242,10 @@
static const String START_ROOT_ISOLATE = 'startRootIsolate';
+ String get patchVersion => emitter.patchVersion;
+
bool get supportsReflection => emitter.emitter.supportsReflection;
- String get patchVersion => USE_LAZY_EMITTER ? 'lazy' : 'full';
-
final Annotations annotations;
/// Reference to the internal library to lookup functions to always inline.
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index e0388d2..f305c76 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -645,7 +645,8 @@
js.Name helperName = glue.getInterceptorName(node.interceptedClasses);
js.Expression globalHolder = glue.getInterceptorLibrary();
return js.js('#.#(#)',
- [globalHolder, helperName, visitExpression(node.input)]);
+ [globalHolder, helperName, visitExpression(node.input)])
+ .withSourceInformation(node.sourceInformation);
}
@override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index de97137..14cc633 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -62,17 +62,10 @@
JavaScriptBackend backend = compiler.backend;
return compiler.withCurrentElement(element, () {
try {
- ClassElement cls = element.enclosingClass;
- String name = element.name;
- String className = cls == null ? null : cls.name;
- LibraryElement library = element.library;
- String libraryName = library == null ? null : library.toString();
// TODO(karlklose): remove this fallback.
// Fallback for a few functions that we know require try-finally and
// switch.
- if (element.isNative ||
- element.isPatched ||
- libraryName == 'origin library(dart:typed_data)') {
+ if (element.isNative) {
compiler.log('Using SSA compiler for platform element $element');
return fallbackCompiler.compile(work);
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 110d156..01ebde7 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -3,9 +3,9 @@
import '../../cps_ir/cps_ir_nodes.dart';
import '../../cps_ir/optimizers.dart' show ParentVisitor;
-import '../../constants/expressions.dart';
import '../../constants/values.dart';
import '../../elements/elements.dart';
+import '../../io/source_information.dart';
import '../../js_backend/codegen/glue.dart';
import '../../dart2jslib.dart' show Selector, World;
import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal;
@@ -82,12 +82,6 @@
visit(function);
}
- @override
- visit(Node node) {
- Node result = node.accept(this);
- return result != null ? result : node;
- }
-
Constant get trueConstant {
return new Constant(new TrueConstantValue());
}
@@ -134,7 +128,8 @@
Primitive nullPrimitive = nullConstant;
Primitive test = new ApplyBuiltinOperator(
BuiltinOperator.Identical,
- <Primitive>[function.parameters.single, nullPrimitive]);
+ <Primitive>[function.parameters.single, nullPrimitive],
+ function.parameters.single.sourceInformation);
Expression newBody =
new LetCont.many(<Continuation>[returnFalse, originalBody],
@@ -165,8 +160,8 @@
Selector selector = new Selector.fromElement(function);
// TODO(johnniwinther): Come up with an implementation of SourceInformation
// for calls such as this one that don't appear in the original source.
- InvokeStatic invoke =
- new InvokeStatic(function, selector, arguments, continuation, null);
+ InvokeStatic invoke = new InvokeStatic(
+ function, selector, arguments, continuation, null);
_parentVisitor.processInvokeStatic(invoke);
LetCont letCont = new LetCont(continuation, invoke);
@@ -176,7 +171,11 @@
letCont.parent = parent;
}
- processLetHandler(LetHandler node) {
+ @override
+ Expression traverseLetHandler(LetHandler node) {
+ assert(node.handler.parameters.length == 2);
+ Parameter previousExceptionParameter = _exceptionParameter;
+
// BEFORE: Handlers have two parameters, exception and stack trace.
// AFTER: Handlers have a single parameter, which is unwrapped to get
// the exception and stack trace.
@@ -200,18 +199,11 @@
assert(stackTraceParameter.hasNoUses);
node.handler.parameters.removeLast();
- }
- @override
- visitLetHandler(LetHandler node) {
- assert(node.handler.parameters.length == 2);
- Parameter previousExceptionParameter = _exceptionParameter;
- _exceptionParameter = node.handler.parameters.first;
- processLetHandler(node);
visit(node.handler);
_exceptionParameter = previousExceptionParameter;
- visit(node.body);
+ return node.body;
}
processThrow(Throw node) {
@@ -236,17 +228,19 @@
/// Returns an interceptor for the given value, capable of responding to
/// [selector].
- ///
+ ///
/// A single getInterceptor call will be created per primitive, bound
/// immediately after the primitive is bound.
- ///
+ ///
/// The type propagation pass will later narrow the set of interceptors
/// based on the input type, and the let sinking pass will propagate the
/// getInterceptor call closer to its use when this is profitable.
- Interceptor getInterceptorFor(Primitive prim, Selector selector) {
+ Interceptor getInterceptorFor(Primitive prim, Selector selector,
+ SourceInformation sourceInformation) {
+ assert(prim is! Interceptor);
Interceptor interceptor = interceptors[prim];
if (interceptor == null) {
- interceptor = new Interceptor(prim);
+ interceptor = new Interceptor(prim, sourceInformation);
interceptors[prim] = interceptor;
InteriorNode parent = prim.parent;
insertLetPrim(interceptor, parent.body);
@@ -273,7 +267,8 @@
// Change 'receiver.foo()' to 'this.foo(receiver)'.
newReceiver = thisParameter;
} else {
- newReceiver = getInterceptorFor(receiver, node.selector);
+ newReceiver = getInterceptorFor(
+ receiver, node.selector, node.sourceInformation);
}
node.arguments.insert(0, node.receiver);
@@ -301,7 +296,8 @@
Primitive t = trueConstant;
Primitive i = new ApplyBuiltinOperator(
BuiltinOperator.Identical,
- <Primitive>[condition.value.definition, t]);
+ <Primitive>[condition.value.definition, t],
+ condition.value.definition.sourceInformation);
LetPrim newNode = new LetPrim(t,
new LetPrim(i,
new Branch(new IsTrue(i),
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index cdcc609..b069aaf 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -43,7 +43,8 @@
if (USE_LAZY_EMITTER) {
emitter = new lazy_js_emitter.Emitter(compiler, namer, nativeEmitter);
} else if (USE_STARTUP_EMITTER) {
- emitter = new startup_js_emitter.Emitter(compiler, namer, nativeEmitter);
+ emitter = new startup_js_emitter.Emitter(
+ compiler, namer, nativeEmitter, generateSourceMap);
} else {
emitter =
new full_js_emitter.Emitter(compiler, namer, generateSourceMap, this);
@@ -53,6 +54,10 @@
String get name => 'Code emitter';
+ /// Returns the string that is used to find library patches that are
+ /// specialized for the emitter.
+ String get patchVersion => emitter.patchVersion;
+
/// Returns the closure expression of a static function.
jsAst.Expression isolateStaticClosureAccess(FunctionElement element) {
return emitter.isolateStaticClosureAccess(element);
@@ -148,6 +153,10 @@
}
abstract class Emitter {
+ /// Returns the string that is used to find library patches that are
+ /// specialized for this emitter.
+ String get patchVersion;
+
/// Uses the [programBuilder] to generate a model of the program, emits
/// the program, and returns the size of the generated output.
int emitProgram(ProgramBuilder programBuilder);
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
index c12637c..10e27921 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
@@ -193,14 +193,15 @@
void emitCheckedClassSetters(Class cls, ClassBuilder builder) {
if (cls.onlyForRti) return;
- for (Field field in cls.fields) {
- if (field.needsCheckedSetter) {
- assert(!field.needsUncheckedSetter);
- compiler.withCurrentElement(field.element, () {
- generateCheckedSetter(
- field.element, field.name, field.accessorName, builder);
- });
- }
+ for (StubMethod method in cls.checkedSetters) {
+ Element member = method.element;
+ assert(member != null);
+ jsAst.Expression code = method.code;
+ jsAst.Name setterName = method.name;
+ compiler.dumpInfoTask.registerElementAst(member,
+ builder.addProperty(setterName, code));
+ generateReflectionDataForFieldGetterOrSetter(
+ member, setterName, builder, isGetter: false);
}
}
@@ -376,19 +377,6 @@
message: '$previousName != ${memberName}'));
}
- void generateCheckedSetter(Element member,
- jsAst.Name fieldName,
- jsAst.Name accessorName,
- ClassBuilder builder) {
- jsAst.Expression code = backend.generatedCode[member];
- assert(code != null);
- jsAst.Name setterName = namer.deriveSetterName(accessorName);
- compiler.dumpInfoTask.registerElementAst(member,
- builder.addProperty(setterName, code));
- generateReflectionDataForFieldGetterOrSetter(
- member, setterName, builder, isGetter: false);
- }
-
void emitGetterForCSP(Element member, jsAst.Name fieldName,
jsAst.Name accessorName,
ClassBuilder builder) {
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
index b0a94ce..ebd7d1a 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
@@ -20,7 +20,7 @@
bool canBeReflected = method.canBeReflected;
bool canTearOff = method.needsTearOff;
jsAst.Name tearOffName = method.tearOffName;
- bool isClosure = method is InstanceMethod && method.isClosure;
+ bool isClosure = method is InstanceMethod && method.isClosureCallMethod;
jsAst.Name superAlias = method is InstanceMethod ? method.aliasName : null;
bool hasSuperAlias = superAlias != null;
jsAst.Expression memberTypeExpression = method.functionType;
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 02a0ac2..60382c1 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -206,6 +206,9 @@
}
@override
+ String get patchVersion => "full";
+
+ @override
bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
if (constant.isFunction) return true; // Already emitted.
if (constant.isPrimitive) return true; // Inlined.
@@ -397,6 +400,13 @@
generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
return jsAst.js.expressionTemplateFor("$typesAccess[#]");
+ case JsBuiltin.createDartClosureFromNameOfStaticFunction:
+ // The global-functions map contains a map from name to tear-off
+ // getters.
+ String functionGettersMap =
+ generateEmbeddedGlobalAccessString(embeddedNames.GLOBAL_FUNCTIONS);
+ return jsAst.js.expressionTemplateFor("$functionGettersMap[#]()");
+
default:
compiler.internalError(NO_LOCATION_SPANNABLE,
"Unhandled Builtin: $builtin");
@@ -838,7 +848,14 @@
NativeGenerator.generateIsolateAffinityTagInitialization(
backend,
generateEmbeddedGlobalAccess,
- js("convertToFastObject", [])));
+ js("""
+ // On V8, the 'intern' function converts a string to a symbol, which
+ // makes property access much faster.
+ function (s) {
+ var o = {};
+ o[s] = 1;
+ return Object.keys(convertToFastObject(o))[0];
+ }""", [])));
}
parts..add(js.comment('BEGIN invoke [main].'))
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 70431c1..810b678 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
@@ -42,6 +42,9 @@
_emitter = new ModelEmitter(compiler, namer, nativeEmitter);
@override
+ String get patchVersion => "lazy";
+
+ @override
int emitProgram(ProgramBuilder programBuilder) {
Program program = programBuilder.buildProgram();
return _emitter.emitProgram(program);
@@ -174,6 +177,9 @@
case JsBuiltin.getType:
return _emitter.templateForReadType;
+ case JsBuiltin.createDartClosureFromNameOfStaticFunction:
+ throw new UnsupportedError('createDartClosureFromNameOfStaticFunction');
+
default:
_compiler.internalError(NO_LOCATION_SPANNABLE,
"Unhandled Builtin: $builtin");
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index ee7030e..b97a47e 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
@@ -235,7 +235,7 @@
NativeGenerator.generateIsolateAffinityTagInitialization(
backend,
generateEmbeddedGlobalAccess,
- // TODO(floitsch): convertToFastObject.
+ // TODO(floitsch): internStringFunction.
js.js("(function(x) { return x; })", []));
} else {
nativeIsolateAffinityTagInitialization = js.js.statement(";");
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index a76c63a..fe83370 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -22,6 +22,10 @@
final bool hasIsolateSupport;
/// A map from load id to the list of fragments that need to be loaded.
final Map<String, List<Fragment>> loadMap;
+ /// A map from names to strings.
+ ///
+ /// This map is needed to support `const Symbol` expressions;
+ final Map<js.Name, String> symbolsMap;
// If this field is not `null` then its value must be emitted in the embedded
// global `TYPE_TO_INTERCEPTOR_MAP`. The map references constants and classes.
@@ -35,6 +39,7 @@
Program(this.fragments,
this.holders,
this.loadMap,
+ this.symbolsMap,
this.typeToInterceptorMap,
this._metadataCollector,
this.finalizers,
@@ -226,6 +231,7 @@
final List<Method> methods;
final List<Field> fields;
final List<StubMethod> isChecks;
+ final List<StubMethod> checkedSetters;
/// Stub methods for this class that are call stubs for getters.
final List<StubMethod> callStubs;
@@ -263,6 +269,7 @@
this.callStubs,
this.typeVariableReaderStubs,
this.noSuchMethodStubs,
+ this.checkedSetters,
this.isChecks,
this.functionTypeIndex,
{this.onlyForRti,
@@ -295,6 +302,7 @@
List<Field> staticFieldsForReflection,
List<StubMethod> callStubs,
List<StubMethod> typeVariableReaderStubs,
+ List<StubMethod> checkedSetters,
List<StubMethod> isChecks,
js.Expression functionTypeIndex,
{bool onlyForRti,
@@ -307,7 +315,9 @@
callStubs,
typeVariableReaderStubs,
const <StubMethod>[],
- isChecks, functionTypeIndex,
+ checkedSetters,
+ isChecks,
+ functionTypeIndex,
onlyForRti: onlyForRti,
isDirectlyInstantiated: isDirectlyInstantiated,
isNative: false);
@@ -356,6 +366,12 @@
bool get needsInterceptedGetter => getterFlags > 1;
bool get needsInterceptedSetter => setterFlags > 1;
+
+ bool get needsInterceptedGetterOnReceiver => getterFlags == 2;
+ bool get needsInterceptedSetterOnReceiver => setterFlags == 2;
+
+ bool get needsInterceptedGetterOnThis => getterFlags == 3;
+ bool get needsInterceptedSetterOnThis => setterFlags == 3;
}
abstract class Method {
@@ -369,7 +385,7 @@
}
/// A method that corresponds to a method in the original Dart program.
-class DartMethod extends Method {
+abstract class DartMethod extends Method {
final bool needsTearOff;
final js.Name tearOffName;
final List<ParameterStubMethod> parameterStubs;
@@ -407,6 +423,8 @@
(requiredParameterCount != null &&
optionalParameterDefaultValues != null));
}
+
+ bool get isStatic;
}
class InstanceMethod extends DartMethod {
@@ -415,7 +433,11 @@
/// ensure that this method is registered on the prototype under both [name]
/// and [aliasName].
final js.Name aliasName;
- final bool isClosure;
+
+ /// True if this is the implicit `call` instance method of an anonymous
+ /// closure. This predicate is false for explicit `call` methods and for
+ /// functions that can be torn off.
+ final bool isClosureCallMethod;
InstanceMethod(Element element, js.Name name, js.Expression code,
@@ -428,7 +450,7 @@
bool canBeReflected,
int requiredParameterCount,
/* List | Map */ optionalParameterDefaultValues,
- this.isClosure,
+ this.isClosureCallMethod,
js.Expression functionType})
: super(element, name, code, parameterStubs, callName,
needsTearOff: needsTearOff,
@@ -438,8 +460,10 @@
requiredParameterCount: requiredParameterCount,
optionalParameterDefaultValues: optionalParameterDefaultValues,
functionType: functionType) {
- assert(isClosure != null);
+ assert(isClosureCallMethod != null);
}
+
+ bool get isStatic => false;
}
/// A method that is generated by the backend and has not direct correspondence
@@ -495,6 +519,8 @@
requiredParameterCount: requiredParameterCount,
optionalParameterDefaultValues: optionalParameterDefaultValues,
functionType: functionType);
+
+ bool get isStatic => true;
}
class StaticStubMethod extends StubMethod implements StaticMethod {
diff --git a/pkg/compiler/lib/src/js_emitter/native_generator.dart b/pkg/compiler/lib/src/js_emitter/native_generator.dart
index 9a4145c..fd15d8a 100644
--- a/pkg/compiler/lib/src/js_emitter/native_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_generator.dart
@@ -17,7 +17,7 @@
static jsAst.Statement generateIsolateAffinityTagInitialization(
JavaScriptBackend backend,
jsAst.Expression generateEmbeddedGlobalAccess(String global),
- jsAst.Expression convertToFastObject) {
+ jsAst.Expression internStringFunction) {
assert(backend.needToInitializeIsolateAffinityTag);
jsAst.Expression getIsolateTagAccess =
@@ -29,13 +29,7 @@
return js.statement('''
!function() {
- // On V8, the 'intern' function converts a string to a symbol, which
- // makes property access much faster.
- function intern(s) {
- var o = {};
- o[s] = 1;
- return Object.keys(#convertToFastObject(o))[0];
- }
+ var intern = #internStringFunction;
#getIsolateTag = function(name) {
return intern("___dart_" + name + #isolateTag);
@@ -63,7 +57,7 @@
}();
''',
{'initializeDispatchProperty': backend.needToInitializeDispatchProperty,
- 'convertToFastObject': convertToFastObject,
+ 'internStringFunction': internStringFunction,
'getIsolateTag': getIsolateTagAccess,
'isolateTag': isolateTagAccess,
'dispatchPropertyName': dispatchPropertyNameAccess});
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 a526b48..1b9b6ef 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
@@ -82,6 +82,13 @@
/// update field-initializers to point to the ConstantModel.
final Map<ConstantValue, Constant> _constants = <ConstantValue, Constant>{};
+ /// Mapping from names to strings.
+ ///
+ /// This mapping is used to support `const Symbol` expressions.
+ ///
+ /// This map is filled when building classes.
+ final Map<js.Name, String> _symbolsMap = <js.Name, String>{};
+
Set<Class> _unneededNativeClasses;
Program buildProgram({bool storeFunctionTypesInMetadata: false}) {
@@ -162,6 +169,7 @@
fragments,
holders,
_buildLoadMap(),
+ _symbolsMap,
_buildTypeToInterceptorMap(),
_task.metadataCollector,
finalizers,
@@ -350,7 +358,7 @@
js.Name name = namer.className(element);
return new Class(
- element, name, null, [], instanceFields, [], [], [], [], [], null,
+ element, name, null, [], instanceFields, [], [], [], [], [], [], null,
isDirectlyInstantiated: true,
onlyForRti: false,
isNative: element.isNative);
@@ -394,10 +402,17 @@
runtimeTypeGenerator.generateTypeVariableReaderStubs(element);
List<StubMethod> noSuchMethodStubs = <StubMethod>[];
+
if (backend.enabledNoSuchMethod && element == _compiler.objectClass) {
Map<js.Name, Selector> selectors =
classStubGenerator.computeSelectorsForNsmHandlers();
selectors.forEach((js.Name name, Selector selector) {
+ // If the program contains `const Symbol` names we have to retain them.
+ String selectorName = selector.name;
+ if (selector.isSetter) selectorName = "$selectorName=";
+ if (backend.symbolsUsed.contains(selectorName)) {
+ _symbolsMap[name] = selectorName;
+ }
noSuchMethodStubs
.add(classStubGenerator.generateStubForNoSuchMethod(name,
selector));
@@ -430,6 +445,18 @@
element,
storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata);
+ List<StubMethod> checkedSetters = <StubMethod>[];
+ for (Field field in instanceFields) {
+ if (field.needsCheckedSetter) {
+ assert(!field.needsUncheckedSetter);
+ Element element = field.element;
+ js.Expression code = backend.generatedCode[element];
+ assert(code != null);
+ js.Name name = namer.deriveSetterName(field.accessorName);
+ checkedSetters.add(_buildStubMethod(name, code, element: element));
+ }
+ }
+
List<StubMethod> isChecks = <StubMethod>[];
typeTests.properties.forEach((js.Name name, js.Node code) {
isChecks.add(_buildStubMethod(name, code));
@@ -454,6 +481,7 @@
staticFieldsForReflection,
callStubs,
typeVariableReaderStubs,
+ checkedSetters,
isChecks,
typeTests.functionTypeIndex,
isDirectlyInstantiated: isInstantiated,
@@ -465,6 +493,7 @@
callStubs,
typeVariableReaderStubs,
noSuchMethodStubs,
+ checkedSetters,
isChecks,
typeTests.functionTypeIndex,
isDirectlyInstantiated: isInstantiated,
@@ -530,7 +559,7 @@
bool canTearOff = false;
js.Name tearOffName;
- bool isClosure = false;
+ bool isClosureCallMethod = false;
bool isNotApplyTarget = !element.isFunction || element.isAccessor;
bool canBeReflected = _methodCanBeReflected(element);
@@ -545,7 +574,7 @@
} else {
if (element.enclosingClass.isClosure) {
canTearOff = false;
- isClosure = true;
+ isClosureCallMethod = true;
} else {
// Careful with operators.
canTearOff = universe.hasInvokedGetter(element, _compiler.world) ||
@@ -599,7 +628,7 @@
return new InstanceMethod(element, name, code,
_generateParameterStubs(element, canTearOff), callName,
needsTearOff: canTearOff, tearOffName: tearOffName,
- isClosure: isClosure, aliasName: aliasName,
+ isClosureCallMethod: isClosureCallMethod, aliasName: aliasName,
canBeApplied: canBeApplied, canBeReflected: canBeReflected,
requiredParameterCount: requiredParameterCount,
optionalParameterDefaultValues: optionalParameterDefaultValues,
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/deferred_fragment_hash.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/deferred_fragment_hash.dart
new file mode 100644
index 0000000..4c09dcf
--- /dev/null
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/deferred_fragment_hash.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart2js.js_emitter.startup_emitter.model_emitter;
+
+class _DeferredFragmentHash extends js.DeferredString {
+ String _hash;
+ final DeferredFragment _fragment;
+
+ _DeferredFragmentHash(this._fragment);
+
+ void setHash(String hash) {
+ assert(_hash == null);
+ _hash = hash;
+ }
+
+ @override
+ String get value {
+ assert(_hash != null);
+ // Note the additional quotes in the returned value.
+ return '"$_hash"';
+ }
+
+ String toString() => "HashCode for ${_fragment} [$_hash]";
+}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index fb5b823..a3f2a13 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -7,6 +7,7 @@
import 'package:js_runtime/shared/embedded_names.dart' show
JsBuiltin,
METADATA,
+ STATIC_FUNCTION_NAME_TO_CLOSURE,
TYPES;
import '../program_builder/program_builder.dart' show ProgramBuilder;
@@ -36,10 +37,15 @@
JavaScriptBackend get _backend => _compiler.backend;
- Emitter(Compiler compiler, Namer namer, NativeEmitter nativeEmitter)
+ Emitter(Compiler compiler, Namer namer, NativeEmitter nativeEmitter,
+ bool shouldGenerateSourceMap)
: this._compiler = compiler,
this.namer = namer,
- _emitter = new ModelEmitter(compiler, namer, nativeEmitter);
+ _emitter = new ModelEmitter(
+ compiler, namer, nativeEmitter, shouldGenerateSourceMap);
+
+ @override
+ String get patchVersion => "startup";
@override
int emitProgram(ProgramBuilder programBuilder) {
@@ -172,6 +178,11 @@
_emitter.generateEmbeddedGlobalAccessString(TYPES);
return js.js.expressionTemplateFor("$typesAccess[#]");
+ case JsBuiltin.createDartClosureFromNameOfStaticFunction:
+ String functionAccess = _emitter.generateEmbeddedGlobalAccessString(
+ STATIC_FUNCTION_NAME_TO_CLOSURE);
+ return js.js.expressionTemplateFor("$functionAccess(#)");
+
default:
_compiler.internalError(NO_LOCATION_SPANNABLE,
"Unhandled Builtin: $builtin");
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 390ecd6..f0b5a78 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -4,6 +4,27 @@
part of dart2js.js_emitter.startup_emitter.model_emitter;
+/// The name of the property that stores the tear-off getter on a static
+/// function.
+///
+/// This property is only used when isolates are used.
+///
+/// When serializing static functions we transmit the
+/// name of the static function, but not the name of the function's getter. We
+/// store the getter-function on the static function itself, which allows us to
+/// find it easily.
+const String tearOffPropertyName = r'$tearOff';
+
+/// The name of the property that stores the list of fields on a constructor.
+///
+/// This property is only used when isolates are used.
+///
+/// When serializing objects we extract all fields from any given object.
+/// We extract the names of all fields from a fresh empty object. This list
+/// is cached on the constructor in this property to to avoid too many
+/// allocations.
+const String cachedClassFieldNames = r'$cachedFieldNames';
+
/// The fast startup emitter's goal is to minimize the amount of work that the
/// JavaScript engine has to do before it can start running user code.
///
@@ -47,17 +68,59 @@
}
}
+var supportsDirectProtoAccess = (function () {
+ var cls = function () {};
+ cls.prototype = {'p': {}};
+ var object = new cls();
+ return object.__proto__ &&
+ object.__proto__.p === cls.prototype.p;
+})();
+
+var functionsHaveName = (function() {
+ function t() {};
+ return (typeof t.name == 'string')
+})();
+
+var isChrome = (typeof window != 'undefined') &&
+ (typeof window.chrome != 'undefined');
+
+// Sets the name property of functions, if the JS engine doesn't set the name
+// itself.
+// As of 2015 only IE doesn't set the name.
+function setFunctionNamesIfNecessary(holders) {
+ if (functionsHaveName) return;
+ for (var i = 0; i < holders.length; i++) {
+ var holder = holders[i];
+ var keys = Object.keys(holder);
+ for (var j = 0; j < keys.length; j++) {
+ var key = keys[j];
+ var f = holder[key];
+ if (typeof f == 'function') f.name = key;
+ }
+ }
+}
+
// Makes [cls] inherit from [sup].
// On Chrome, Firefox and recent IEs this happens by updating the internal
// proto-property of the classes 'prototype' field.
// Older IEs use `Object.create` and copy over the properties.
function inherit(cls, sup) {
- // TODO(floitsch): IE doesn't support changing the __proto__ property. There,
- // we need to copy the properties instead.
cls.#typeNameProperty = cls.name; // Needed for RTI.
cls.prototype.constructor = cls;
cls.prototype[#operatorIsPrefix + cls.name] = cls;
- cls.prototype.__proto__ = sup.prototype;
+
+ // The superclass is only null for the Dart Object.
+ if (sup != null) {
+ if (supportsDirectProtoAccess) {
+ // Firefox doesn't like to update the prototypes, but when setting up
+ // the hierarchy chain it's ok.
+ cls.prototype.__proto__ = sup.prototype;
+ return;
+ }
+ var clsPrototype = Object.create(sup.prototype);
+ copyProperties(cls.prototype, clsPrototype);
+ cls.prototype = clsPrototype;
+ }
}
// Mixes in the properties of [mixin] into [cls].
@@ -71,14 +134,19 @@
// getter ([getterName]) to access the field. If the field wasn't set before
// the first access, it is initialized with the [initializer].
function lazy(holder, name, getterName, initializer) {
- holder[name] = null;
+ var uninitializedSentinel = holder;
+ holder[name] = uninitializedSentinel;
holder[getterName] = function() {
holder[getterName] = function() { #cyclicThrow(name) };
var result;
var sentinelInProgress = initializer;
try {
- result = holder[name] = sentinelInProgress;
- result = holder[name] = initializer();
+ if (holder[name] === uninitializedSentinel) {
+ result = holder[name] = sentinelInProgress;
+ result = holder[name] = initializer();
+ } else {
+ result = holder[name];
+ }
} finally {
// Use try-finally, not try-catch/throw as it destroys the stack
// trace.
@@ -108,7 +176,74 @@
return list;
}
-// TODO(floitsch): provide code for tear-offs.
+function convertToFastObject(properties) {
+ // Create an instance that uses 'properties' as prototype. This should
+ // make 'properties' a fast object.
+ function t() {};
+ t.prototype = properties;
+ new t();
+ return properties;
+}
+
+// This variable is used by the tearOffCode to guarantee unique functions per
+// tear-offs.
+var functionCounter = 0;
+#tearOffCode;
+
+// Each deferred hunk comes with its own types which are added to the end
+// of the types-array.
+// The `funTypes` passed to the `installTearOff` function below is relative to
+// the hunk the function comes from. The `typesOffset` variable encodes the
+// offset at which the new types will be added.
+var typesOffset = 0;
+
+// Adapts the stored data, so it's suitable for a tearOff call.
+//
+// Stores the tear-off getter-function in the [container]'s [getterName]
+// property.
+//
+// The [container] is either a class (that is, its prototype), or the holder for
+// static functions.
+//
+// The argument [funsOrNames] is an array of strings or functions. If it is a
+// name, then the function should be fetched from the container. The first
+// entry in that array *must* be a string.
+//
+// TODO(floitsch): Change tearOffCode to accept the data directly, or create a
+// different tearOffCode?
+function installTearOff(
+ container, getterName, isStatic, isIntercepted, requiredParameterCount,
+ optionalParameterDefaultValues, callNames, funsOrNames, funType) {
+ // A function can have several stubs (for example to fill in optional
+ // arguments). We collect these functions in the `funs` array.
+ var funs = [];
+ for (var i = 0; i < funsOrNames.length; i++) {
+ var fun = funsOrNames[i];
+ if ((typeof fun) == 'string') fun = container[fun];
+ fun.#callName = callNames[i];
+ funs.push(fun);
+ }
+
+ // The main function to which all stubs redirect.
+ var fun = funs[0];
+
+ fun[#argumentCount] = requiredParameterCount;
+ fun[#defaultArgumentValues] = optionalParameterDefaultValues;
+ var reflectionInfo = funType;
+ if (typeof reflectionInfo == "number") {
+ // The reflectionInfo can either be a function, or a pointer into the types
+ // table. If it points into the types-table we need to update the index,
+ // in case the tear-off is part of a deferred hunk.
+ reflectionInfo = reflectionInfo + typesOffset;
+ }
+ var name = funsOrNames[0];
+ var getterFunction =
+ tearOff(funs, reflectionInfo, isStatic, name, isIntercepted);
+ container[getterName] = getterFunction;
+ if (isStatic) {
+ fun.$tearOffPropertyName = getterFunction;
+ }
+}
// Instead of setting the interceptor tags directly we use this update
// function. This makes it easier for deferred fragments to contribute to the
@@ -137,32 +272,63 @@
// Updates the types embedded global.
function updateTypes(newTypes) {
var types = #embeddedTypes;
+ // This relies on the fact that types are added *after* the tear-offs have
+ // been installed. The tear-off function uses the types-length to figure
+ // out at which offset its types are located. If the types were added earlier
+ // the offset would be wrong.
types.push.apply(types, newTypes);
}
// Updates the given holder with the properties of the [newHolder].
// This function is used when a deferred fragment is initialized.
function updateHolder(holder, newHolder) {
- // TODO(floitsch): updating the prototype (instead of copying) is
- // *horribly* inefficient in Firefox. There we should just copy the
- // properties.
- var oldPrototype = holder.__proto__;
- newHolder.__proto__ = oldPrototype;
- holder.__proto__ = newHolder;
+ // Firefox doesn't like when important objects have their prototype chain
+ // updated. We therefore do this only on V8.
+ if (isChrome) {
+ var oldPrototype = holder.__proto__;
+ newHolder.__proto__ = oldPrototype;
+ holder.__proto__ = newHolder;
+ } else {
+ copyProperties(newHolder, holder);
+ }
return holder;
}
// Every deferred hunk (i.e. fragment) is a function that we can invoke to
// initialize it. At this moment it contributes its data to the main hunk.
function initializeDeferredHunk(hunk) {
+ // Update the typesOffset for the next deferred library.
+ typesOffset = #embeddedTypes.length;
+
// TODO(floitsch): extend natives.
- hunk(derive, mixin, lazy, makeConstList, installTearOff,
- updateHolder, updateTypes, updateInterceptorsByTag, updateLeafTags,
- #embeddedGlobalsObject, #holdersList, #currentIsolate);
+ hunk(inherit, mixin, lazy, makeConstList, convertToFastObject, installTearOff,
+ setFunctionNamesIfNecessary, updateHolder, updateTypes,
+ setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
+ #embeddedGlobalsObject, #holdersList, #staticState);
+}
+
+// Returns the global with the given [name].
+function getGlobalFromName(name) {
+ // TODO(floitsch): we are running through all holders. Since negative
+ // lookups are expensive we might need to improve this.
+ // Relies on the fact that all names are unique across all holders.
+ for (var i = 0; i < holders.length; i++) {
+ // The constant holder reuses the same names. Therefore we must skip it.
+ if (holders[i] == #constantHolderReference) continue;
+ // Relies on the fact that all variables are unique.
+ if (holders[i][name]) return holders[i][name];
+ }
}
// Creates the holders.
#holders;
+
+// If the name is not set on the functions, do it now.
+setFunctionNamesIfNecessary(#holdersList);
+
+// TODO(floitsch): we should build this object as a literal.
+var #staticStateDeclaration = {};
+
// Sets the prototypes of classes.
#prototypes;
// Sets aliases of methods (on the prototypes of classes).
@@ -172,13 +338,6 @@
// Builds the inheritance structure.
#inheritance;
-// Emits the embedded globals.
-#embeddedGlobals;
-
-// Sets up the native support.
-// Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
-#nativeSupport;
-
// Instantiates all constants.
#constants;
// Initializes the static non-final fields (with their constant values).
@@ -186,6 +345,13 @@
// Creates lazy getters for statics that must run initializers on first access.
#lazyStatics;
+// Emits the embedded globals.
+#embeddedGlobals;
+
+// Sets up the native support.
+// Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
+#nativeSupport;
+
// Invokes main (making sure that it records the 'current-script' value).
#invokeMain;
})();
@@ -197,15 +363,17 @@
/// For example, once the holders have been created, they are included into
/// the main holders.
const String deferredBoilerplate = '''
-{
-#deferredInitializers.current =
-function(derive, mixin, lazy, makeConstList, installTearOff,
- updateHolder, updateTypes,
- setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
- #embeddedGlobalsObject, holdersList, #currentIsolate) {
+function(inherit, mixin, lazy, makeConstList, convertToFastObject,
+ installTearOff, setFunctionNamesIfNecessary, updateHolder, updateTypes,
+ setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
+ #embeddedGlobalsObject, holdersList, #staticState) {
// Builds the holders. They only contain the data for new holders.
#holders;
+
+// If the name is not set on the functions, do it now.
+setFunctionNamesIfNecessary(#deferredHoldersList);
+
// Updates the holders of the main-fragment. Uses the provided holdersList to
// access the main holders.
// The local holders are replaced by the combined holders. This is necessary
@@ -220,11 +388,6 @@
// Builds the inheritance structure.
#inheritance;
-updateTypes(#types);
-
-// Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
-#nativeSupport;
-
// Instantiates all constants of this deferred fragment.
// Note that the constant-holder has been updated earlier and storing the
// constant values in the constant-holder makes them available globally.
@@ -233,10 +396,11 @@
#staticNonFinalFields;
// Creates lazy getters for statics that must run initializers on first access.
#lazyStatics;
-};
-// TODO(floitsch): this last line should be outside the AST, since it
-// requires to know the hash of the part of the code above this comment.
-#deferredInitializers[#hash] = #deferredInitializers.current;
+
+updateTypes(#types);
+
+// Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
+#nativeSupport;
}''';
/**
@@ -263,14 +427,880 @@
js.Expression generateConstantReference(ConstantValue value) =>
modelEmitter.generateConstantReference(value);
- js.Statement emitMainFragment(Program program) {
- MainFragment fragment = program.fragments.first;
- throw new UnimplementedError('emitMain');
+ js.Expression classReference(Class cls) {
+ return js.js('#.#', [cls.holder.name, cls.name]);
}
- js.Statement emitDeferredFragment(DeferredFragment fragment,
- js.Expression deferredTypes,
- List<Holder> holders) {
- throw new UnimplementedError('emitDeferred');
+ js.Statement emitMainFragment(
+ Program program,
+ Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) {
+ MainFragment fragment = program.fragments.first;
+
+ Iterable<Holder> nonStaticStateHolders = program.holders
+ .where((Holder holder) => !holder.isStaticStateHolder);
+
+ return js.js.statement(mainBoilerplate,
+ {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap),
+ 'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
+ 'cyclicThrow': backend.emitter.staticFunctionAccess(
+ backend.getCyclicThrowHelper()),
+ 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
+ 'tearOffCode': new js.Block(buildTearOffCode(backend)),
+ 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES),
+ 'embeddedInterceptorTags':
+ generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
+ 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
+ 'embeddedGlobalsObject': js.js("init"),
+ 'holdersList': new js.ArrayInitializer(nonStaticStateHolders
+ .map((holder) => js.js("#", holder.name))
+ .toList(growable: false)),
+ 'staticStateDeclaration': new js.VariableDeclaration(
+ namer.staticStateHolder, allowRename: false),
+ 'staticState': js.js('#', namer.staticStateHolder),
+ 'constantHolderReference': buildConstantHolderReference(program),
+ 'holders': emitHolders(program.holders, fragment),
+ 'callName': js.string(namer.callNameField),
+ 'argumentCount': js.string(namer.requiredParameterField),
+ 'defaultArgumentValues': js.string(namer.defaultValuesField),
+ 'prototypes': emitPrototypes(fragment),
+ 'inheritance': emitInheritance(fragment),
+ 'aliases': emitInstanceMethodAliases(fragment),
+ 'tearOffs': emitInstallTearOffs(fragment),
+ 'constants': emitConstants(fragment),
+ 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
+ 'lazyStatics': emitLazilyInitializedStatics(fragment),
+ 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes),
+ 'nativeSupport': program.needsNativeSupport
+ ? emitNativeSupport(fragment)
+ : new js.EmptyStatement(),
+ 'invokeMain': fragment.invokeMain,
+ });
}
-}
\ No newline at end of file
+
+ js.Expression emitDeferredFragment(DeferredFragment fragment,
+ js.Expression deferredTypes,
+ List<Holder> holders) {
+ List<Holder> nonStaticStateHolders = holders
+ .where((Holder holder) => !holder.isStaticStateHolder)
+ .toList(growable: false);
+
+ List<js.Statement> updateHolderAssignments = <js.Statement>[];
+ for (int i = 0; i < nonStaticStateHolders.length; i++) {
+ Holder holder = nonStaticStateHolders[i];
+ updateHolderAssignments.add(js.js.statement(
+ '#holder = updateHolder(holdersList[#index], #holder)',
+ {'index': js.number(i),
+ 'holder': new js.VariableUse(holder.name)}));
+ }
+
+ // TODO(floitsch): don't just reference 'init'.
+ return js.js(deferredBoilerplate,
+ {'embeddedGlobalsObject': new js.Parameter('init'),
+ 'staticState': new js.Parameter(namer.staticStateHolder),
+ 'holders': emitHolders(holders, fragment),
+ 'deferredHoldersList': new js.ArrayInitializer(nonStaticStateHolders
+ .map((holder) => js.js("#", holder.name))
+ .toList(growable: false)),
+ 'updateHolders': new js.Block(updateHolderAssignments),
+ 'prototypes': emitPrototypes(fragment),
+ 'inheritance': emitInheritance(fragment),
+ 'aliases': emitInstanceMethodAliases(fragment),
+ 'tearOffs': emitInstallTearOffs(fragment),
+ 'constants': emitConstants(fragment),
+ 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
+ 'lazyStatics': emitLazilyInitializedStatics(fragment),
+ 'types': deferredTypes,
+ // TODO(floitsch): only call emitNativeSupport if we need native.
+ 'nativeSupport': emitNativeSupport(fragment),
+ });
+ }
+
+ js.Statement emitDeferredInitializerGlobal(Map loadMap) {
+ if (loadMap.isEmpty) return new js.Block.empty();
+
+ return js.js.statement("""
+ if (typeof(${ModelEmitter.deferredInitializersGlobal}) === 'undefined')
+ var ${ModelEmitter.deferredInitializersGlobal} = Object.create(null);""");
+ }
+
+ /// Emits all holders, except for the static-state holder.
+ ///
+ /// The emitted holders contain classes (only the constructors) and all
+ /// static functions.
+ js.Statement emitHolders(List<Holder> holders, Fragment fragment) {
+ // Skip the static-state holder in this function.
+ holders = holders
+ .where((Holder holder) => !holder.isStaticStateHolder)
+ .toList(growable: false);
+
+ Map<Holder, Map<js.Name, js.Expression>> holderCode =
+ <Holder, Map<js.Name, js.Expression>>{};
+
+ for (Holder holder in holders) {
+ holderCode[holder] = <js.Name, js.Expression>{};
+ }
+
+ for (Library library in fragment.libraries) {
+ for (StaticMethod method in library.statics) {
+ assert(!method.holder.isStaticStateHolder);
+ holderCode[method.holder].addAll(emitStaticMethod(method));
+ }
+ for (Class cls in library.classes) {
+ assert(!cls.holder.isStaticStateHolder);
+ holderCode[cls.holder][cls.name] = emitConstructor(cls);
+ }
+ }
+
+ js.VariableInitialization emitHolderInitialization(Holder holder) {
+ List<js.Property> properties = <js.Property>[];
+ holderCode[holder].forEach((js.Name key, js.Expression value) {
+ properties.add(new js.Property(js.quoteName(key), value));
+ });
+
+ return new js.VariableInitialization(
+ new js.VariableDeclaration(holder.name, allowRename: false),
+ new js.ObjectInitializer(properties));
+ }
+
+ // The generated code looks like this:
+ //
+ // {
+ // var H = {...}, ..., G = {...};
+ // var holders = [ H, ..., G ];
+ // }
+
+ List<js.Statement> statements = [
+ new js.ExpressionStatement(
+ new js.VariableDeclarationList(holders
+ .map(emitHolderInitialization)
+ .toList())),
+ js.js.statement('var holders = #', new js.ArrayInitializer(
+ holders
+ .map((holder) => new js.VariableUse(holder.name))
+ .toList(growable: false)))];
+ return new js.Block(statements);
+ }
+
+ /// Returns a reference to the constant holder, or the JS-literal `null`.
+ js.Expression buildConstantHolderReference(Program program) {
+ Holder constantHolder = program.holders
+ .firstWhere((Holder holder) => holder.isConstantsHolder,
+ orElse: () => null);
+ if (constantHolder == null) return new js.LiteralNull();
+ return new js.VariableUse(constantHolder.name);
+ }
+
+ /// Emits the given [method].
+ ///
+ /// A Dart method might result in several JavaScript functions, if it
+ /// requires stubs. The returned map contains the original method and all
+ /// the stubs it needs.
+ Map<js.Name, js.Expression> emitStaticMethod(StaticMethod method) {
+ Map<js.Name, js.Expression> jsMethods = <js.Name, js.Expression>{};
+
+ // We don't need to install stub-methods. They can only be used when there
+ // are tear-offs, in which case they are emitted there.
+ assert(() {
+ if (method is StaticDartMethod) {
+ return method.needsTearOff || method.parameterStubs.isEmpty;
+ }
+ return true;
+ });
+ jsMethods[method.name] = method.code;
+
+ return jsMethods;
+ }
+
+ /// Emits a constructor for the given class [cls].
+ ///
+ /// The constructor is statically built.
+ js.Expression emitConstructor(Class cls) {
+ List<js.Name> fieldNames = const <js.Name>[];
+
+ // If the class is not directly instantiated we only need it for inheritance
+ // or RTI. In either case we don't need its fields.
+ if (cls.isDirectlyInstantiated && !cls.isNative) {
+ fieldNames = cls.fields.map((Field field) => field.name).toList();
+ }
+ js.Name name = cls.name;
+
+ Iterable<js.Name> assignments = fieldNames.map((js.Name field) {
+ return js.js("this.#field = #field", {"field": field});
+ });
+
+ return js.js('function #(#) { # }', [name, fieldNames, assignments]);
+ }
+
+ /// Emits the prototype-section of the fragment.
+ ///
+ /// This section updates the prototype-property of all constructors in the
+ /// global holders.
+ js.Statement emitPrototypes(Fragment fragment) {
+ List<js.Statement> assignments = fragment.libraries
+ .expand((Library library) => library.classes)
+ .map((Class cls) => js.js.statement(
+ '#.prototype = #;',
+ [classReference(cls), emitPrototype(cls)]))
+ .toList(growable: false);
+
+ return new js.Block(assignments);
+ }
+
+ /// Emits the prototype of the given class [cls].
+ ///
+ /// The prototype is generated as object literal. Inheritance is ignored.
+ ///
+ /// The prototype also includes the `is-property` that every class must have.
+ // TODO(floitsch): we could avoid that property if we knew that it wasn't
+ // needed.
+ js.Expression emitPrototype(Class cls) {
+ Iterable<Method> methods = cls.methods;
+ Iterable<Method> checkedSetters = cls.checkedSetters;
+ Iterable<Method> isChecks = cls.isChecks;
+ Iterable<Method> callStubs = cls.callStubs;
+ Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs;
+ Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs;
+ Iterable<Method> gettersSetters = generateGettersSetters(cls);
+ Iterable<Method> allMethods =
+ [methods, checkedSetters, isChecks, callStubs, typeVariableReaderStubs,
+ noSuchMethodStubs, gettersSetters].expand((x) => x);
+
+ List<js.Property> properties = <js.Property>[];
+
+ if (cls.superclass == null) {
+ properties.add(new js.Property(js.string("constructor"),
+ classReference(cls)));
+ properties.add(new js.Property(namer.operatorIs(cls.element),
+ js.number(1)));
+ }
+
+ allMethods.forEach((Method method) {
+ emitInstanceMethod(method)
+ .forEach((js.Expression name, js.Expression code) {
+ properties.add(new js.Property(name, code));
+ });
+ });
+
+ return new js.ObjectInitializer(properties);
+ }
+
+ /// Generates a getter for the given [field].
+ Method generateGetter(Field field) {
+ assert(field.needsGetter);
+
+ String template;
+ if (field.needsInterceptedGetterOnReceiver) {
+ template = "function(receiver) { return receiver[#]; }";
+ } else if (field.needsInterceptedGetterOnThis) {
+ template = "function(receiver) { return this[#]; }";
+ } else {
+ assert(!field.needsInterceptedGetter);
+ template = "function() { return this[#]; }";
+ }
+ js.Expression fieldName = js.quoteName(field.name);
+ js.Expression code = js.js(template, fieldName);
+ js.Name getterName = namer.deriveGetterName(field.accessorName);
+ return new StubMethod(getterName, code);
+ }
+
+ /// Generates a setter for the given [field].
+ Method generateSetter(Field field) {
+ assert(field.needsUncheckedSetter);
+
+ String template;
+ if (field.needsInterceptedSetterOnReceiver) {
+ template = "function(receiver, val) { return receiver[#] = val; }";
+ } else if (field.needsInterceptedSetterOnThis) {
+ template = "function(receiver, val) { return this[#] = val; }";
+ } else {
+ assert(!field.needsInterceptedSetter);
+ template = "function(val) { return this[#] = val; }";
+ }
+
+ js.Expression fieldName = js.quoteName(field.name);
+ js.Expression code = js.js(template, fieldName);
+ js.Name setterName = namer.deriveSetterName(field.accessorName);
+ return new StubMethod(setterName, code);
+ }
+
+ /// Generates all getters and setters the given class [cls] needs.
+ Iterable<Method> generateGettersSetters(Class cls) {
+ Iterable<Method> getters = cls.fields
+ .where((Field field) => field.needsGetter)
+ .map(generateGetter);
+
+ Iterable<Method> setters = cls.fields
+ .where((Field field) => field.needsUncheckedSetter)
+ .map(generateSetter);
+
+ return [getters, setters].expand((x) => x);
+ }
+
+ /// Emits the given instance [method].
+ ///
+ /// The given method may be a stub-method (for example for is-checks).
+ ///
+ /// If it is a Dart-method, all necessary stub-methods are emitted, too. In
+ /// that case the returned map contains more than just one entry.
+ ///
+ /// If the method is a closure call-method, also returns the necessary
+ /// properties in case the closure can be applied.
+ Map<js.Expression, js.Expression> emitInstanceMethod(Method method) {
+ var properties = <js.Expression, js.Expression>{};
+
+ properties[method.name] = method.code;
+ if (method is InstanceMethod) {
+ for (ParameterStubMethod stubMethod in method.parameterStubs) {
+ properties[stubMethod.name] = stubMethod.code;
+ }
+
+ if (method.isClosureCallMethod && method.canBeApplied) {
+ properties[js.string(namer.callCatchAllName)] =
+ js.quoteName(method.name);
+ properties[js.string(namer.requiredParameterField)] =
+ js.number(method.requiredParameterCount);
+ properties[js.string(namer.defaultValuesField)] =
+ _encodeOptionalParameterDefaultValues(method);
+ }
+ }
+
+ return properties;
+ }
+
+ /// Emits the inheritance block of the fragment.
+ ///
+ /// In this section prototype chains are updated and mixin functions are
+ /// copied.
+ js.Statement emitInheritance(Fragment fragment) {
+ List<js.Expression> inheritCalls = <js.Expression>[];
+ List<js.Expression> mixinCalls = <js.Expression>[];
+
+ for (Library library in fragment.libraries) {
+ for (Class cls in library.classes) {
+ js.Expression superclassReference = (cls.superclass == null)
+ ? new js.LiteralNull()
+ : classReference(cls.superclass);
+
+ inheritCalls.add(js.js('inherit(#, #)',
+ [classReference(cls), superclassReference]));
+
+ if (cls.isMixinApplication) {
+ MixinApplication mixin = cls;
+ mixinCalls.add(js.js('mixin(#, #)',
+ [classReference(cls), classReference(mixin.mixinClass)]));
+ }
+ }
+ }
+
+ return new js.Block([inheritCalls, mixinCalls]
+ .expand((e) => e)
+ .map((e) => new js.ExpressionStatement(e))
+ .toList(growable: false));
+ }
+
+ /// Emits the setup of method aliases.
+ ///
+ /// This step consists of simply copying JavaScript functions to their
+ /// aliased names so they point to the same function.
+ js.Statement emitInstanceMethodAliases(Fragment fragment) {
+ List<js.Statement> assignments = <js.Statement>[];
+
+ for (Library library in fragment.libraries) {
+ for (Class cls in library.classes) {
+ for (InstanceMethod method in cls.methods) {
+ if (method.aliasName != null) {
+ assignments.add(js.js.statement(
+ '#.prototype.# = #.prototype.#',
+ [classReference(cls), js.quoteName(method.aliasName),
+ classReference(cls), js.quoteName(method.name)]));
+
+ }
+ }
+ }
+ }
+ return new js.Block(assignments);
+ }
+
+ /// Encodes the optional default values so that the runtime Function.apply
+ /// can use them.
+ js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) {
+ // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole].
+ if (method.optionalParameterDefaultValues is List) {
+ List<ConstantValue> defaultValues = method.optionalParameterDefaultValues;
+ Iterable<js.Expression> elements =
+ defaultValues.map(generateConstantReference);
+ return js.js('function() { return #; }',
+ new js.ArrayInitializer(elements.toList()));
+ } else {
+ Map<String, ConstantValue> defaultValues =
+ method.optionalParameterDefaultValues;
+ List<js.Property> properties = <js.Property>[];
+ List<String> names = defaultValues.keys.toList(growable: false);
+ // Sort the names the same way we sort them for the named-argument calling
+ // convention.
+ names.sort();
+
+ for (String name in names) {
+ ConstantValue value = defaultValues[name];
+ properties.add(new js.Property(js.string(name),
+ generateConstantReference(value)));
+ }
+ return js.js('function() { return #; }',
+ new js.ObjectInitializer(properties));
+ }
+ }
+
+ /// Emits the statement that installs a tear off for a method.
+ ///
+ /// Tear-offs might be passed to `Function.apply` which means that all
+ /// calling-conventions (with or without optional positional/named arguments)
+ /// are possible. As such, the tear-off needs enough information to fill in
+ /// missing parameters.
+ js.Statement emitInstallTearOff(js.Expression container, DartMethod method) {
+ List<js.Name> callNames = <js.Name>[];
+ List<js.Expression> funsOrNames = <js.Expression>[];
+
+ /// Adds the stub-method's code or name to the [funsOrNames] array.
+ ///
+ /// Static methods don't need stub-methods except for tear-offs. As such,
+ /// they are not emitted in the prototype, but directly passed here.
+ ///
+ /// Instance-methods install the stub-methods in their prototype, and we
+ /// use string-based redirections to find them there.
+ void addFunOrName(StubMethod stubMethod) {
+ if (method.isStatic) {
+ funsOrNames.add(stubMethod.code);
+ } else {
+ funsOrNames.add(js.quoteName(stubMethod.name));
+ }
+ }
+
+ callNames.add(method.callName);
+ // The first entry in the funsOrNames-array must be a string.
+ funsOrNames.add(js.quoteName(method.name));
+ for (ParameterStubMethod stubMethod in method.parameterStubs) {
+ callNames.add(stubMethod.callName);
+ addFunOrName(stubMethod);
+ }
+
+ js.ArrayInitializer callNameArray =
+ new js.ArrayInitializer(callNames.map(js.quoteName).toList());
+ js.ArrayInitializer funsOrNamesArray = new js.ArrayInitializer(funsOrNames);
+
+ bool isIntercepted = false;
+ if (method is InstanceMethod) {
+ isIntercepted = backend.isInterceptedMethod(method.element);
+ }
+ int requiredParameterCount = 0;
+ js.Expression optionalParameterDefaultValues = new js.LiteralNull();
+ if (method.canBeApplied) {
+ requiredParameterCount = method.requiredParameterCount;
+ optionalParameterDefaultValues =
+ _encodeOptionalParameterDefaultValues(method);
+ }
+
+ return js.js.statement('''
+ installTearOff(#container, #getterName, #isStatic, #isIntercepted,
+ #requiredParameterCount, #optionalParameterDefaultValues,
+ #callNames, #funsOrNames, #funType)''',
+ {
+ "container": container,
+ "getterName": js.quoteName(method.tearOffName),
+ "isStatic": new js.LiteralBool(method.isStatic),
+ "isIntercepted": new js.LiteralBool(isIntercepted),
+ "requiredParameterCount": js.number(requiredParameterCount),
+ "optionalParameterDefaultValues": optionalParameterDefaultValues,
+ "callNames": callNameArray,
+ "funsOrNames": funsOrNamesArray,
+ "funType": method.functionType,
+ });
+ }
+
+ /// Emits the section that installs tear-off getters.
+ js.Statement emitInstallTearOffs(Fragment fragment) {
+ List<js.Statement> inits = <js.Statement>[];
+
+ for (Library library in fragment.libraries) {
+ for (StaticMethod method in library.statics) {
+ // TODO(floitsch): can there be anything else than a StaticDartMethod?
+ if (method is StaticDartMethod) {
+ if (method.needsTearOff) {
+ Holder holder = method.holder;
+ inits.add(
+ emitInstallTearOff(new js.VariableUse(holder.name), method));
+ }
+ }
+ }
+ for (Class cls in library.classes) {
+ for (InstanceMethod method in cls.methods) {
+ if (method.needsTearOff) {
+ js.Expression container = js.js("#.prototype", classReference(cls));
+ inits.add(emitInstallTearOff(container, method));
+ }
+ }
+ }
+ }
+ return new js.Block(inits);
+ }
+
+ /// Emits the constants section.
+ js.Statement emitConstants(Fragment fragment) {
+ List<js.Statement> assignments = <js.Statement>[];
+ for (Constant constant in fragment.constants) {
+ // TODO(floitsch): instead of just updating the constant holder, we should
+ // find the constants that don't have any dependency on other constants
+ // and create an object-literal with them (and assign it to the
+ // constant-holder variable).
+ assignments.add(js.js.statement('#.# = #',
+ [constant.holder.name,
+ constant.name,
+ constantEmitter.generate(constant.value)]));
+ }
+ return new js.Block(assignments);
+ }
+
+
+ /// Emits the static non-final fields section.
+ ///
+ /// This section initializes all static non-final fields that don't require
+ /// an initializer.
+ js.Block emitStaticNonFinalFields(Fragment fragment) {
+ List<StaticField> fields = fragment.staticNonFinalFields;
+ // TODO(floitsch): instead of assigning the fields one-by-one we should
+ // create a literal and assign it to the static-state holder.
+ // TODO(floitsch): if we don't make a literal we should at least initialize
+ // statics that have the same initial value in the same expression:
+ // `$.x = $.y = $.z = null;`.
+ Iterable<js.Statement> statements = fields.map((StaticField field) {
+ assert(field.holder.isStaticStateHolder);
+ return js.js.statement("#.# = #;",
+ [field.holder.name, field.name, field.code]);
+ });
+ return new js.Block(statements.toList());
+ }
+
+ /// Emits lazy fields.
+ ///
+ /// This section initializes all static (final and non-final) fields that
+ /// require an initializer.
+ js.Block emitLazilyInitializedStatics(Fragment fragment) {
+ List<StaticField> fields = fragment.staticLazilyInitializedFields;
+ Iterable<js.Statement> statements = fields.map((StaticField field) {
+ assert(field.holder.isStaticStateHolder);
+ return js.js.statement("lazy(#, #, #, #);",
+ [field.holder.name,
+ js.quoteName(field.name),
+ js.quoteName(namer.deriveLazyInitializerName(field.name)),
+ field.code]);
+ });
+
+ return new js.Block(statements.toList());
+ }
+
+ /// Emits the embedded globals that are needed for deferred loading.
+ ///
+ /// This function is only invoked for the main fragment.
+ ///
+ /// The [loadMap] contains a map from load-ids (for each deferred library)
+ /// to the list of generated fragments that must be installed when the
+ /// deferred library is loaded.
+ Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading(
+ Map<String, List<Fragment>> loadMap,
+ Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) {
+ if (loadMap.isEmpty) return [];
+
+ List<js.Property> globals = <js.Property>[];
+
+ js.ArrayInitializer fragmentUris(List<Fragment> fragments) {
+ return js.stringArray(fragments.map((DeferredFragment fragment) =>
+ "${fragment.outputFileName}.${ModelEmitter.deferredExtension}"));
+ }
+ js.ArrayInitializer fragmentHashes(List<Fragment> fragments) {
+ return new js.ArrayInitializer(
+ fragments
+ .map((fragment) => deferredLoadHashes[fragment])
+ .toList(growable: false));
+ }
+
+ List<js.Property> uris = new List<js.Property>(loadMap.length);
+ List<js.Property> hashes = new List<js.Property>(loadMap.length);
+ int count = 0;
+ loadMap.forEach((String loadId, List<Fragment> fragmentList) {
+ uris[count] =
+ new js.Property(js.string(loadId), fragmentUris(fragmentList));
+ hashes[count] =
+ new js.Property(js.string(loadId), fragmentHashes(fragmentList));
+ count++;
+ });
+
+ globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS),
+ new js.ObjectInitializer(uris)));
+ globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES),
+ new js.ObjectInitializer(hashes)));
+ globals.add(new js.Property(js.string(DEFERRED_INITIALIZED),
+ js.js("Object.create(null)")));
+
+ String deferredGlobal = ModelEmitter.deferredInitializersGlobal;
+ js.Expression isHunkLoadedFunction =
+ js.js("function(hash) { return !!$deferredGlobal[hash]; }");
+ globals.add(new js.Property(js.string(IS_HUNK_LOADED),
+ isHunkLoadedFunction));
+
+ js.Expression isHunkInitializedFunction =
+ js.js("function(hash) { return !!#deferredInitialized[hash]; }",
+ {'deferredInitialized':
+ generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED)});
+ globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED),
+ isHunkInitializedFunction));
+
+ /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the
+ /// deferred hunk.
+ js.Expression initializeLoadedHunkFunction =
+ js.js("""
+ function(hash) {
+ initializeDeferredHunk($deferredGlobal[hash]);
+ #deferredInitialized[hash] = true;
+ }""", {'deferredInitialized':
+ generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED)});
+
+ globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK),
+ initializeLoadedHunkFunction));
+
+ return globals;
+ }
+
+ /// Emits the [MANGLED_GLOBAL_NAMES] embedded global.
+ ///
+ /// This global maps minified names for selected classes (some important
+ /// core classes, and some native classes) to their unminified names.
+ js.Property emitMangledGlobalNames() {
+ List<js.Property> names = <js.Property>[];
+
+ // We want to keep the original names for the most common core classes when
+ // calling toString on them.
+ List<ClassElement> nativeClassesNeedingUnmangledName =
+ [compiler.intClass, compiler.doubleClass, compiler.numClass,
+ compiler.stringClass, compiler.boolClass, compiler.nullClass,
+ compiler.listClass];
+ // TODO(floitsch): this should probably be on a per-fragment basis.
+ nativeClassesNeedingUnmangledName.forEach((element) {
+ names.add(new js.Property(js.quoteName(namer.className(element)),
+ js.string(element.name)));
+ });
+
+ return new js.Property(js.string(MANGLED_GLOBAL_NAMES),
+ new js.ObjectInitializer(names));
+ }
+
+ /// Emits the [GET_TYPE_FROM_NAME] embedded global.
+ ///
+ /// This embedded global provides a way to go from a class name (which is
+ /// also the constructor's name) to the constructor itself.
+ js.Property emitGetTypeFromName() {
+ js.Expression function = js.js("getGlobalFromName");
+ return new js.Property(js.string(GET_TYPE_FROM_NAME), function);
+ }
+
+ /// Emits the [METADATA] embedded global.
+ ///
+ /// The metadata itself has already been computed earlier and is stored in
+ /// the [program].
+ List<js.Property> emitMetadata(Program program) {
+ List<js.Property> metadataGlobals = <js.Property>[];
+
+ js.Property createGlobal(js.Expression metadata, String global) {
+ return new js.Property(js.string(global), metadata);
+ }
+
+ metadataGlobals.add(createGlobal(program.metadata, METADATA));
+ js.Expression types =
+ program.metadataTypesForOutputUnit(program.mainFragment.outputUnit);
+ metadataGlobals.add(createGlobal(types, TYPES));
+
+ return metadataGlobals;
+ }
+
+ /// Emits all embedded globals.
+ js.Statement emitEmbeddedGlobals(
+ Program program,
+ Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) {
+ List<js.Property> globals = <js.Property>[];
+
+ if (program.loadMap.isNotEmpty) {
+ globals.addAll(emitEmbeddedGlobalsForDeferredLoading(
+ program.loadMap, deferredLoadHashes));
+ }
+
+ if (program.typeToInterceptorMap != null) {
+ globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP),
+ program.typeToInterceptorMap));
+ }
+
+ if (program.hasIsolateSupport) {
+ String staticStateName = namer.staticStateHolder;
+ // TODO(floitsch): this doesn't create a new isolate, but just reuses
+ // the current static state. Since we don't run multiple isolates in the
+ // same JavaScript context (except for testing) this shouldn't have any
+ // impact on real-world programs, though.
+ globals.add(
+ new js.Property(js.string(CREATE_NEW_ISOLATE),
+ js.js('function () { return $staticStateName; }')));
+
+ js.Expression nameToClosureFunction = js.js('''
+ // First fetch the static function. From there we can execute its
+ // getter function which builds a Dart closure.
+ function(name) {
+ var staticFunction = getGlobalFromName(name);
+ var getterFunction = staticFunction.$tearOffPropertyName;
+ return getterFunction();
+ }''');
+ globals.add(new js.Property(js.string(STATIC_FUNCTION_NAME_TO_CLOSURE),
+ nameToClosureFunction));
+
+ globals.add(
+ new js.Property(js.string(CLASS_ID_EXTRACTOR),
+ js.js('function(o) { return o.constructor.name; }')));
+
+ js.Expression extractFieldsFunction = js.js('''
+ function(o) {
+ var constructor = o.constructor;
+ var fieldNames = constructor.$cachedClassFieldNames;
+ if (!fieldNames) {
+ // Extract the fields from an empty unmodified object.
+ var empty = new constructor();
+ // This gives us the keys that the constructor sets.
+ fieldNames = constructor.$cachedClassFieldNames = Object.keys(empty);
+ }
+ var result = new Array(fieldNames.length);
+ for (var i = 0; i < fieldNames.length; i++) {
+ result[i] = o[fieldNames[i]];
+ }
+ return result;
+ }''');
+ globals.add(new js.Property(js.string(CLASS_FIELDS_EXTRACTOR),
+ extractFieldsFunction));
+
+ js.Expression createInstanceFromClassIdFunction = js.js('''
+ function(name) {
+ var constructor = getGlobalFromName(name);
+ return new constructor();
+ }
+ ''');
+ globals.add(new js.Property(js.string(INSTANCE_FROM_CLASS_ID),
+ createInstanceFromClassIdFunction));
+
+ js.Expression initializeEmptyInstanceFunction = js.js('''
+ function(name, o, fields) {
+ var constructor = o.constructor;
+ // By construction the object `o` is an empty object with the same
+ // keys as the one we used in the extract-fields function.
+ var fieldNames = Object.keys(o);
+ if (fieldNames.length != fields.length) {
+ throw new Error("Mismatch during deserialization.");
+ }
+ for (var i = 0; i < fields.length; i++) {
+ o[fieldNames[i]] = fields[i];
+ }
+ return o;
+ }''');
+ globals.add(new js.Property(js.string(INITIALIZE_EMPTY_INSTANCE),
+ initializeEmptyInstanceFunction));
+ }
+
+ globals.add(emitMangledGlobalNames());
+
+ // The [MANGLED_NAMES] table must contain the mapping for const symbols.
+ // Without const symbols, the table is only relevant for reflection and
+ // therefore unused in this emitter.
+ List<js.Property> mangledNamesProperties = <js.Property>[];
+ program.symbolsMap.forEach((js.Name mangledName, String unmangledName) {
+ mangledNamesProperties.add(
+ new js.Property(mangledName, js.string(unmangledName)));
+ });
+ globals.add(new js.Property(
+ js.string(MANGLED_NAMES),
+ new js.ObjectInitializer(mangledNamesProperties)));
+
+ globals.add(emitGetTypeFromName());
+
+ globals.addAll(emitMetadata(program));
+
+ if (program.needsNativeSupport) {
+ globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG),
+ new js.LiteralNull()));
+ globals.add(new js.Property(js.string(LEAF_TAGS),
+ new js.LiteralNull()));
+ }
+
+ js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals);
+
+ return js.js.statement('var init = #;', globalsObject);
+ }
+
+ /// Emits data needed for native classes.
+ ///
+ /// We don't try to reduce the size of the native data, but rather build
+ /// JavaScript object literals that contain all the information directly.
+ /// This means that the output size is bigger, but that the startup is faster.
+ ///
+ /// This function is the static equivalent of
+ /// [NativeGenerator.buildNativeInfoHandler].
+ js.Statement emitNativeSupport(Fragment fragment) {
+ List<js.Statement> statements = <js.Statement>[];
+
+ // The isolate-affinity tag must only be initialized once per program.
+ if (fragment.isMainFragment &&
+ NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
+ statements.add(NativeGenerator.generateIsolateAffinityTagInitialization(
+ backend,
+ generateEmbeddedGlobalAccess,
+ js.js("""
+ // On V8, the 'intern' function converts a string to a symbol, which
+ // makes property access much faster.
+ function (s) {
+ var o = {};
+ o[s] = 1;
+ return Object.keys(convertToFastObject(o))[0];
+ }""", [])));
+ }
+
+ Map<String, js.Expression> interceptorsByTag = <String, js.Expression>{};
+ Map<String, js.Expression> leafTags = <String, js.Expression>{};
+ js.Statement subclassAssignment = new js.EmptyStatement();
+
+ for (Library library in fragment.libraries) {
+ for (Class cls in library.classes) {
+ if (cls.nativeLeafTags != null) {
+ for (String tag in cls.nativeLeafTags) {
+ interceptorsByTag[tag] = classReference(cls);
+ leafTags[tag] = new js.LiteralBool(true);
+ }
+ }
+ if (cls.nativeNonLeafTags != null) {
+ for (String tag in cls.nativeNonLeafTags) {
+ interceptorsByTag[tag] = classReference(cls);
+ leafTags[tag] = new js.LiteralBool(false);
+ }
+ if (cls.nativeExtensions != null) {
+ List<Class> subclasses = cls.nativeExtensions;
+ js.Expression value = js.string(cls.nativeNonLeafTags[0]);
+ for (Class subclass in subclasses) {
+ value = js.js('#.# = #',
+ [classReference(subclass),
+ NATIVE_SUPERCLASS_TAG_NAME,
+ js.string(cls.nativeNonLeafTags[0])]);
+ }
+ subclassAssignment = new js.ExpressionStatement(value);
+ }
+ }
+ }
+ }
+ statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);",
+ js.objectLiteral(interceptorsByTag)));
+ statements.add(js.js.statement("setOrUpdateLeafTags(#);",
+ js.objectLiteral(leafTags)));
+ statements.add(subclassAssignment);
+
+ return new js.Block(statements);
+ }
+}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 9797dbb..e30c58b 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -4,37 +4,65 @@
library dart2js.js_emitter.startup_emitter.model_emitter;
+import 'dart:convert' show JsonEncoder;
+
+import '../../common.dart';
+
import '../../constants/values.dart' show ConstantValue, FunctionConstantValue;
import '../../dart2jslib.dart' show Compiler;
import '../../elements/elements.dart' show ClassElement, FunctionElement;
+import '../../hash/sha1.dart' show Hasher;
+
+import '../../io/code_output.dart';
+
+import '../../io/line_column_provider.dart' show
+ LineColumnCollector,
+ LineColumnProvider;
+
+import '../../io/source_map_builder.dart' show
+ SourceMapBuilder;
+
import '../../js/js.dart' as js;
import '../../js_backend/js_backend.dart' show
JavaScriptBackend,
Namer,
ConstantEmitter;
+import '../../util/util.dart' show
+ NO_LOCATION_SPANNABLE;
+
+import '../../util/uri_extras.dart' show
+ relativize;
+
import '../js_emitter.dart' show AstContainer, NativeEmitter;
import 'package:js_runtime/shared/embedded_names.dart' show
+ CLASS_FIELDS_EXTRACTOR,
+ CLASS_ID_EXTRACTOR,
CREATE_NEW_ISOLATE,
DEFERRED_INITIALIZED,
DEFERRED_LIBRARY_URIS,
DEFERRED_LIBRARY_HASHES,
GET_TYPE_FROM_NAME,
+ INITIALIZE_EMPTY_INSTANCE,
INITIALIZE_LOADED_HUNK,
+ INSTANCE_FROM_CLASS_ID,
INTERCEPTORS_BY_TAG,
IS_HUNK_INITIALIZED,
IS_HUNK_LOADED,
LEAF_TAGS,
MANGLED_GLOBAL_NAMES,
+ MANGLED_NAMES,
METADATA,
NATIVE_SUPERCLASS_TAG_NAME,
+ STATIC_FUNCTION_NAME_TO_CLOSURE,
TYPE_TO_INTERCEPTOR_MAP,
TYPES;
import '../js_emitter.dart' show NativeGenerator, buildTearOffCode;
import '../model.dart';
+part 'deferred_fragment_hash.dart';
part 'fragment_emitter.dart';
class ModelEmitter {
@@ -42,6 +70,11 @@
final Namer namer;
ConstantEmitter constantEmitter;
final NativeEmitter nativeEmitter;
+ final bool shouldGenerateSourceMap;
+
+ // The full code that is written to each hunk part-file.
+ final Map<Fragment, CodeOutput> outputBuffers = <Fragment, CodeOutput>{};
+
JavaScriptBackend get backend => compiler.backend;
@@ -53,7 +86,8 @@
static const String typeNameProperty = r"builtin$cls";
- ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter)
+ ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter,
+ this.shouldGenerateSourceMap)
: this.compiler = compiler,
this.namer = namer {
this.constantEmitter = new ConstantEmitter(
@@ -126,55 +160,239 @@
}
int emitProgram(Program program) {
- List<Fragment> fragments = program.fragments;
- MainFragment mainFragment = fragments.first;
-
- int totalSize = 0;
+ MainFragment mainFragment = program.fragments.first;
+ List<DeferredFragment> deferredFragments =
+ new List<DeferredFragment>.from(program.fragments.skip(1));
FragmentEmitter fragmentEmitter =
new FragmentEmitter(compiler, namer, backend, constantEmitter, this);
- // We have to emit the deferred fragments first, since we need their
- // deferred hash (which depends on the output) when emitting the main
- // fragment.
- List<js.Expression> fragmentsCode = fragments.skip(1).map(
- (DeferredFragment deferredFragment) {
- js.Expression types =
- program.metadataTypesForOutputUnit(deferredFragment.outputUnit);
- return fragmentEmitter.emitDeferredFragment(
- deferredFragment, types, program.holders);
- }).toList();
+ Map<DeferredFragment, _DeferredFragmentHash> deferredHashTokens =
+ new Map<DeferredFragment, _DeferredFragmentHash>();
+ for (DeferredFragment fragment in deferredFragments) {
+ deferredHashTokens[fragment] = new _DeferredFragmentHash(fragment);
+ }
- js.Statement mainAst = fragmentEmitter.emitMainFragment(program);
+ js.Statement mainCode =
+ fragmentEmitter.emitMainFragment(program, deferredHashTokens);
+
+ Map<DeferredFragment, js.Expression> deferredFragmentsCode =
+ <DeferredFragment, js.Expression>{};
+
+ for (DeferredFragment fragment in deferredFragments) {
+ js.Expression types =
+ program.metadataTypesForOutputUnit(fragment.outputUnit);
+ deferredFragmentsCode[fragment] = fragmentEmitter.emitDeferredFragment(
+ fragment, types, program.holders);
+ }
js.TokenCounter counter = new js.TokenCounter();
- fragmentsCode.forEach(counter.countTokens);
- counter.countTokens(mainAst);
+ deferredFragmentsCode.values.forEach(counter.countTokens);
+ counter.countTokens(mainCode);
program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
- for (int i = 0; i < fragmentsCode.length; ++i) {
- String code = js.prettyPrint(fragmentsCode[i], compiler).getText();
- totalSize += code.length;
- compiler.outputProvider(fragments[i+1].outputFileName, deferredExtension)
- ..add(code)
- ..close();
+ Map<DeferredFragment, String> hunkHashes =
+ writeDeferredFragments(deferredFragmentsCode);
+
+ // Now that we have written the deferred hunks, we can update the hash
+ // tokens in the main-fragment.
+ deferredHashTokens.forEach((DeferredFragment key,
+ _DeferredFragmentHash token) {
+ token.setHash(hunkHashes[key]);
+ });
+
+ writeMainFragment(mainFragment, mainCode);
+
+ if (backend.requiresPreamble &&
+ !backend.htmlLibraryIsLoaded) {
+ compiler.reportHint(NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
}
- String mainCode = js.prettyPrint(mainAst, compiler).getText();
- compiler.outputProvider(mainFragment.outputFileName, 'js')
- ..add(buildGeneratedBy(compiler))
- ..add(mainCode)
- ..close();
- totalSize += mainCode.length;
-
- return totalSize;
+ if (compiler.deferredMapUri != null) {
+ writeDeferredMap();
+ }
+
+ // Return the total program size.
+ return outputBuffers.values.fold(0, (a, b) => a + b.length);
}
+ /// Generates a simple header that provides the compiler's build id.
String buildGeneratedBy(compiler) {
var suffix = '';
if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
return '// Generated by dart2js (fast startup), '
'the Dart to JavaScript compiler$suffix.\n';
}
+
+ /// Writes all deferred fragment's code into files.
+ ///
+ /// Returns a map from fragment to its hashcode (as used for the deferred
+ /// library code).
+ ///
+ /// Updates the shared [outputBuffers] field with the output.
+ Map<DeferredFragment, String> writeDeferredFragments(
+ Map<DeferredFragment, js.Expression> fragmentsCode) {
+ Map<DeferredFragment, String> hunkHashes = <DeferredFragment, String>{};
+
+ fragmentsCode.forEach((DeferredFragment fragment, js.Expression code) {
+ hunkHashes[fragment] = writeDeferredFragment(fragment, code);
+ });
+
+ return hunkHashes;
+ }
+
+ // Writes the given [fragment]'s [code] into a file.
+ //
+ // Updates the shared [outputBuffers] field with the output.
+ void writeMainFragment(MainFragment fragment, js.Statement code) {
+ LineColumnCollector lineColumnCollector;
+ List<CodeOutputListener> codeOutputListeners;
+ if (shouldGenerateSourceMap) {
+ lineColumnCollector = new LineColumnCollector();
+ codeOutputListeners = <CodeOutputListener>[lineColumnCollector];
+ }
+
+ CodeOutput mainOutput = new StreamCodeOutput(
+ compiler.outputProvider('', 'js'),
+ codeOutputListeners);
+ outputBuffers[fragment] = mainOutput;
+
+ mainOutput.addBuffer(js.prettyPrint(code, compiler,
+ monitor: compiler.dumpInfoTask));
+
+ if (shouldGenerateSourceMap) {
+ mainOutput.add(
+ generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri));
+ }
+
+ mainOutput.close();
+
+ if (shouldGenerateSourceMap) {
+ outputSourceMap(mainOutput, lineColumnCollector, '',
+ compiler.sourceMapUri, compiler.outputUri);
+ }
+ }
+
+ // Writes the given [fragment]'s [code] into a file.
+ //
+ // Returns the deferred fragment's hash.
+ //
+ // Updates the shared [outputBuffers] field with the output.
+ String writeDeferredFragment(DeferredFragment fragment, js.Expression code) {
+ List<CodeOutputListener> outputListeners = <CodeOutputListener>[];
+ Hasher hasher = new Hasher();
+ outputListeners.add(hasher);
+
+ LineColumnCollector lineColumnCollector;
+ if (shouldGenerateSourceMap) {
+ lineColumnCollector = new LineColumnCollector();
+ outputListeners.add(lineColumnCollector);
+ }
+
+ String hunkPrefix = fragment.outputFileName;
+
+ CodeOutput output = new StreamCodeOutput(
+ compiler.outputProvider(hunkPrefix, deferredExtension),
+ outputListeners);
+
+ outputBuffers[fragment] = output;
+
+ // The [code] contains the function that must be invoked when the deferred
+ // hunk is loaded.
+ // That function must be in a map from its hashcode to the function. Since
+ // we don't know the hash before we actually emit the code we store the
+ // function in a temporary field first:
+ //
+ // deferredInitializer.current = <pretty-printed code>;
+ // deferredInitializer[<hash>] = deferredInitializer.current;
+
+ output.add('\n${deferredInitializersGlobal}.current = ');
+
+ output.addBuffer(js.prettyPrint(code, compiler,
+ monitor: compiler.dumpInfoTask));
+
+ // Make a unique hash of the code (before the sourcemaps are added)
+ // This will be used to retrieve the initializing function from the global
+ // variable.
+ String hash = hasher.getHash();
+
+ // Now we copy the deferredInitializer.current into its correct hash.
+ output.add('\n${deferredInitializersGlobal}["$hash"] = '
+ '${deferredInitializersGlobal}.current');
+
+ if (shouldGenerateSourceMap) {
+ Uri mapUri, partUri;
+ Uri sourceMapUri = compiler.sourceMapUri;
+ Uri outputUri = compiler.outputUri;
+
+ if (sourceMapUri != null) {
+ String mapFileName =
+ hunkPrefix + deferredExtension + ".map";
+ List<String> mapSegments = sourceMapUri.pathSegments.toList();
+ mapSegments[mapSegments.length - 1] = mapFileName;
+ mapUri = compiler.sourceMapUri.replace(pathSegments: mapSegments);
+ }
+
+ if (outputUri != null) {
+ String hunkFileName = hunkPrefix + deferredExtension;
+ List<String> partSegments = outputUri.pathSegments.toList();
+ partSegments[partSegments.length - 1] = hunkFileName;
+ partUri = compiler.outputUri.replace(pathSegments: partSegments);
+ }
+
+ output.add(generateSourceMapTag(mapUri, partUri));
+ output.close();
+ outputSourceMap(output, lineColumnCollector, hunkPrefix, mapUri, partUri);
+ } else {
+ output.close();
+ }
+
+ return hash;
+ }
+
+ String generateSourceMapTag(Uri sourceMapUri, Uri fileUri) {
+ if (sourceMapUri != null && fileUri != null) {
+ String sourceMapFileName = relativize(fileUri, sourceMapUri, false);
+ return '''
+
+//# sourceMappingURL=$sourceMapFileName
+''';
+ }
+ return '';
+ }
+
+
+ void outputSourceMap(CodeOutput output,
+ LineColumnProvider lineColumnProvider,
+ String name,
+ [Uri sourceMapUri,
+ Uri fileUri]) {
+ if (!shouldGenerateSourceMap) return;
+ // Create a source file for the compilation output. This allows using
+ // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder].
+ SourceMapBuilder sourceMapBuilder =
+ new SourceMapBuilder(sourceMapUri, fileUri, lineColumnProvider);
+ output.forEachSourceLocation(sourceMapBuilder.addMapping);
+ String sourceMap = sourceMapBuilder.build();
+ compiler.outputProvider(name, 'js.map')
+ ..add(sourceMap)
+ ..close();
+ }
+
+ /// Writes a mapping from library-name to hunk files.
+ ///
+ /// The output is written into a separate file that can be used by outside
+ /// tools.
+ void writeDeferredMap() {
+ Map<String, dynamic> mapping = new Map<String, dynamic>();
+ // Json does not support comments, so we embed the explanation in the
+ // data.
+ mapping["_comment"] = "This mapping shows which compiled `.js` files are "
+ "needed for a given deferred library import.";
+ mapping.addAll(compiler.deferredLoadTask.computeDeferredMap());
+ compiler.outputProvider(compiler.deferredMapUri.path, 'deferred_map')
+ ..add(const JsonEncoder.withIndent(" ").convert(mapping))
+ ..close();
+ }
}
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index 3e6acb5..9919cee 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -530,15 +530,15 @@
/// loaded as well.
Future<LibraryElement> loadDeserializedLibrary(
LibraryDependencyHandler handler,
- LibraryElement library) async {
+ LibraryElement library) {
compiler.onLibraryCreated(library);
libraryCanonicalUriMap[library.canonicalUri] = library;
- await compiler.onLibraryScanned(library, handler);
- for (LibraryTag tag in library.tags) {
- LibraryElement dependency = library.getLibraryFromTag(tag);
- await createLibrary(handler, library, dependency.canonicalUri);
- }
- return library;
+ return compiler.onLibraryScanned(library, handler).then((_) {
+ return Future.forEach(library.tags, (LibraryTag tag) {
+ LibraryElement dependency = library.getLibraryFromTag(tag);
+ return createLibrary(handler, library, dependency.canonicalUri);
+ }).then((_) => library);
+ });
}
/**
diff --git a/pkg/compiler/lib/src/old_to_new_api.dart b/pkg/compiler/lib/src/old_to_new_api.dart
index 34d6e79..59bbc19 100644
--- a/pkg/compiler/lib/src/old_to_new_api.dart
+++ b/pkg/compiler/lib/src/old_to_new_api.dart
@@ -31,8 +31,8 @@
LegacyCompilerDiagnostics(this._handler);
@override
- void report(Uri uri, int begin, int end,
- String message, Diagnostic kind) {
+ void report(var code, Uri uri, int begin, int end,
+ String message, Diagnostic kind) {
_handler(uri, begin, end, message, kind);
}
}
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 297897b..a639a58 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -440,6 +440,8 @@
return const PatchVersion('full');
} else if (annotation.beginToken.next.value == 'patch_lazy') {
return const PatchVersion('lazy');
+ } else if (annotation.beginToken.next.value == 'patch_startup') {
+ return const PatchVersion('startup');
}
}
return null;
diff --git a/pkg/compiler/lib/src/resolution/access_semantics.dart b/pkg/compiler/lib/src/resolution/access_semantics.dart
index 2c741b3..834a043 100644
--- a/pkg/compiler/lib/src/resolution/access_semantics.dart
+++ b/pkg/compiler/lib/src/resolution/access_semantics.dart
@@ -143,6 +143,10 @@
/// The destination of the access is unresolved super access.
UNRESOLVED_SUPER,
+
+ /// The destination is invalid as an access. For instance a prefix used
+ /// as an expression.
+ INVALID,
}
enum CompoundAccessKind {
@@ -178,7 +182,7 @@
/// Read from a superclass getter and write to a superclass field.
SUPER_GETTER_FIELD,
- /// Read from a superclass where the getter (and maybe setter) is unresolved.
+ /// Read from a superclass where the getter is unresolved.
UNRESOLVED_SUPER_GETTER,
/// Read from a superclass getter and write to an unresolved setter.
UNRESOLVED_SUPER_SETTER,
@@ -227,6 +231,14 @@
ConstantExpression get constant => null;
+ /// The element for the getter in case of a compound access,
+ /// [element] otherwise.
+ Element get getter => element;
+
+ /// The element for the setter in case of a compound access,
+ /// [element] otherwise.
+ Element get setter => element;
+
AccessSemantics.expression()
: kind = AccessKind.EXPRESSION;
@@ -357,6 +369,9 @@
StaticAccess.unresolvedSuper(this.element)
: super._(AccessKind.UNRESOLVED_SUPER);
+
+ StaticAccess.invalid(this.element)
+ : super._(AccessKind.INVALID);
}
class CompoundAccessSemantics extends AccessSemantics {
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index ea44ed2..a67de98 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -874,26 +874,36 @@
}
}
- /// Check that access to `super` is currently allowed.
- bool checkSuperAccess(Send node) {
+ /// Check that access to `super` is currently allowed. Returns an
+ /// [AccessSemantics] in case of an error, `null` otherwise.
+ AccessSemantics checkSuperAccess(Send node) {
if (!inInstanceContext) {
- compiler.reportError(node, MessageKind.NO_SUPER_IN_STATIC);
- return false;
+ return new StaticAccess.invalid(
+ reportAndCreateErroneousElement(
+ node, 'super',
+ MessageKind.NO_SUPER_IN_STATIC, {},
+ isError: true));
}
if (node.isConditional) {
// `super?.foo` is not allowed.
- compiler.reportError(node, MessageKind.INVALID_USE_OF_SUPER);
- return false;
+ return new StaticAccess.invalid(
+ reportAndCreateErroneousElement(
+ node, 'super',
+ MessageKind.INVALID_USE_OF_SUPER, {},
+ isError: true));
}
if (currentClass.supertype == null) {
// This is just to guard against internal errors, so no need
// for a real error message.
- compiler.reportError(node, MessageKind.GENERIC,
- {'text': "Object has no superclass"});
- return false;
+ return new StaticAccess.invalid(
+ reportAndCreateErroneousElement(
+ node, 'super',
+ MessageKind.GENERIC,
+ {'text': "Object has no superclass"},
+ isError: true));
}
registry.registerSuperUse(node);
- return true;
+ return null;
}
/// Check that access to `this` is currently allowed.
@@ -926,6 +936,78 @@
}
}
+ /// Compute the [AccessSemantics] corresponding to a compound super access
+ /// reading from [getter] and writing to [setter].
+ AccessSemantics computeCompoundSuperAccessSemantics(
+ Spannable node,
+ Element getter,
+ Element setter) {
+ if (getter.isErroneous) {
+ if (setter.isErroneous) {
+ return new StaticAccess.unresolvedSuper(getter);
+ } else if (setter.isFunction) {
+ assert(invariant(node, setter.name == '[]=',
+ message: "Unexpected super setter '$setter'."));
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, setter);
+ } else {
+ assert(invariant(node, setter.isSetter,
+ message: "Unexpected super setter '$setter'."));
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, setter);
+ }
+ } else if (getter.isField) {
+ if (setter.isField) {
+ if (getter == setter) {
+ return new StaticAccess.superField(getter);
+ } else {
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.SUPER_FIELD_FIELD, getter, setter);
+ }
+ } else {
+ // Either the field is accessible directly, or a setter shadows the
+ // setter access. If there was another instance member it would shadow
+ // the field.
+ assert(invariant(node, setter.isSetter,
+ message: "Unexpected super setter '$setter'."));
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.SUPER_FIELD_SETTER, getter, setter);
+ }
+ } else if (getter.isGetter) {
+ if (setter.isErroneous) {
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, setter);
+ } else if (setter.isField) {
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.SUPER_GETTER_FIELD, getter, setter);
+ } else {
+ assert(invariant(node, setter.isSetter,
+ message: "Unexpected super setter '$setter'."));
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.SUPER_GETTER_SETTER, getter, setter);
+ }
+ } else {
+ assert(invariant(node, getter.isFunction,
+ message: "Unexpected super getter '$getter'."));
+ if (setter.isErroneous) {
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, setter);
+ } else if (setter.isFunction) {
+ assert(invariant(node, getter.name == '[]',
+ message: "Unexpected super getter '$getter'."));
+ assert(invariant(node, setter.name == '[]=',
+ message: "Unexpected super setter '$setter'."));
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.SUPER_GETTER_SETTER, getter, setter);
+ } else {
+ assert(invariant(node, setter.isSetter,
+ message: "Unexpected super setter '$setter'."));
+ return new CompoundAccessSemantics(
+ CompoundAccessKind.SUPER_METHOD_SETTER, getter, setter);
+ }
+ }
+ }
+
/// Compute the [AccessSemantics] corresponding to a local access of [target].
AccessSemantics computeLocalAccessSemantics(Spannable node,
LocalElement target) {
@@ -1043,6 +1125,55 @@
return computeSuperAccessSemantics(node, target);
}
+ /// Compute the [AccessSemantics] for accessing the name of [selector] on the
+ /// super class.
+ ///
+ /// If no matching super member is found and error is reported and
+ /// `noSuchMethod` on `super` is registered. Furthermore, if [alternateName]
+ /// is provided, the [AccessSemantics] corresponding to the alternate name is
+ /// returned. For instance, the access of a super setter for an unresolved
+ /// getter:
+ ///
+ /// class Super {
+ /// set name(_) {}
+ /// }
+ /// class Sub extends Super {
+ /// foo => super.name; // Access to the setter.
+ /// }
+ ///
+ AccessSemantics computeSuperAccessSemanticsForSelectors(
+ Spannable node,
+ Selector getterSelector, Selector setterSelector) {
+
+ // TODO(johnniwinther): Ensure correct behavior if currentClass is a
+ // patch.
+ Element getter = currentClass.lookupSuperByName(getterSelector.memberName);
+ // [target] may be null which means invoking noSuchMethod on super.
+ if (getter == null) {
+ getter = reportAndCreateErroneousElement(
+ node, getterSelector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
+ {'className': currentClass.name, 'memberName': getterSelector.name});
+ // We still need to register the invocation, because we might
+ // call `super.noSuchMethod` which calls [JSInvocationMirror._invokeOn].
+ registry.registerDynamicInvocation(
+ new UniverseSelector(getterSelector, null));
+ registry.registerSuperNoSuchMethod();
+ }
+ Element setter = currentClass.lookupSuperByName(setterSelector.memberName);
+ // [target] may be null which means invoking noSuchMethod on super.
+ if (setter == null) {
+ setter = reportAndCreateErroneousElement(
+ node, setterSelector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
+ {'className': currentClass.name, 'memberName': setterSelector.name});
+ // We still need to register the invocation, because we might
+ // call `super.noSuchMethod` which calls [JSInvocationMirror._invokeOn].
+ registry.registerDynamicInvocation(
+ new UniverseSelector(setterSelector, null));
+ registry.registerSuperNoSuchMethod();
+ }
+ return computeCompoundSuperAccessSemantics(node, getter, setter);
+ }
+
/// Resolve [node] as a subexpression that is _not_ the prefix of a member
/// access. For instance `a` in `a + b`, as opposed to `a` in `a.b`.
ResolutionResult visitExpression(Node node) {
@@ -1151,7 +1282,8 @@
AccessSemantics semantics;
if (node.isSuperCall) {
- if (checkSuperAccess(node)) {
+ semantics = checkSuperAccess(node);
+ if (semantics == null) {
semantics = computeSuperAccessSemanticsForSelector(node, selector);
// TODO(johnniwinther): Add information to [AccessSemantics] about
// whether it is erroneous.
@@ -1197,8 +1329,6 @@
}
}
if (semantics != null) {
- // TODO(johnniwinther): Support invalid super access as an
- // [AccessSemantics].
registry.registerSendStructure(node,
new UnaryStructure(semantics, operator));
}
@@ -1325,7 +1455,8 @@
registry.setSelector(node, selector);
if (node.isSuperCall) {
- if (checkSuperAccess(node)) {
+ semantics = checkSuperAccess(node);
+ if (semantics == null) {
semantics = computeSuperAccessSemanticsForSelector(node, selector);
// TODO(johnniwinther): Add information to [AccessSemantics] about
// whether it is erroneous.
@@ -1552,71 +1683,78 @@
} else {
selector = new Selector(SelectorKind.GETTER, name, callStructure);
}
- if (checkSuperAccess(node)) {
- AccessSemantics semantics = computeSuperAccessSemanticsForSelector(
+ AccessSemantics semantics = checkSuperAccess(node);
+ if (semantics == null) {
+ semantics = computeSuperAccessSemanticsForSelector(
node, selector, alternateName: name.setter);
- if (node.isCall) {
- bool isIncompatibleInvoke = false;
- switch (semantics.kind) {
- case AccessKind.SUPER_METHOD:
- MethodElementX superMethod = semantics.element;
- superMethod.computeSignature(compiler);
- if (!callStructure.signatureApplies(
- superMethod.functionSignature)) {
- registry.registerThrowNoSuchMethod();
- registry.registerDynamicInvocation(
- new UniverseSelector(selector, null));
- registry.registerSuperNoSuchMethod();
- isIncompatibleInvoke = true;
- } else {
- registry.registerStaticInvocation(semantics.element);
- }
- break;
- case AccessKind.SUPER_FIELD:
- case AccessKind.SUPER_FINAL_FIELD:
- case AccessKind.SUPER_GETTER:
- registry.registerStaticUse(semantics.element);
- selector = callStructure.callSelector;
+ }
+ if (node.isCall) {
+ bool isIncompatibleInvoke = false;
+ switch (semantics.kind) {
+ case AccessKind.SUPER_METHOD:
+ MethodElementX superMethod = semantics.element;
+ superMethod.computeSignature(compiler);
+ if (!callStructure.signatureApplies(
+ superMethod.functionSignature)) {
+ registry.registerThrowNoSuchMethod();
registry.registerDynamicInvocation(
new UniverseSelector(selector, null));
- break;
- case AccessKind.SUPER_SETTER:
- case AccessKind.UNRESOLVED_SUPER:
- // NoSuchMethod registered in [computeSuperSemantics].
- break;
- default:
- internalError(node, "Unexpected super property access $semantics.");
- break;
- }
- registry.registerSendStructure(node,
- isIncompatibleInvoke
- ? new IncompatibleInvokeStructure(semantics, selector)
- : new InvokeStructure(semantics, selector));
- } else {
- switch (semantics.kind) {
- case AccessKind.SUPER_METHOD:
- // TODO(johnniwinther): Method this should be registered as a
- // closurization.
- registry.registerStaticUse(semantics.element);
- break;
- case AccessKind.SUPER_FIELD:
- case AccessKind.SUPER_FINAL_FIELD:
- case AccessKind.SUPER_GETTER:
- registry.registerStaticUse(semantics.element);
- break;
- case AccessKind.SUPER_SETTER:
- case AccessKind.UNRESOLVED_SUPER:
- // NoSuchMethod registered in [computeSuperSemantics].
- break;
- default:
- internalError(node, "Unexpected super property access $semantics.");
- break;
- }
- registry.registerSendStructure(node,
- new GetStructure(semantics, selector));
+ registry.registerSuperNoSuchMethod();
+ isIncompatibleInvoke = true;
+ } else {
+ registry.registerStaticInvocation(semantics.element);
+ }
+ break;
+ case AccessKind.SUPER_FIELD:
+ case AccessKind.SUPER_FINAL_FIELD:
+ case AccessKind.SUPER_GETTER:
+ registry.registerStaticUse(semantics.element);
+ selector = callStructure.callSelector;
+ registry.registerDynamicInvocation(
+ new UniverseSelector(selector, null));
+ break;
+ case AccessKind.SUPER_SETTER:
+ case AccessKind.UNRESOLVED_SUPER:
+ // NoSuchMethod registered in [computeSuperSemantics].
+ break;
+ case AccessKind.INVALID:
+ // 'super' is not allowed.
+ break;
+ default:
+ internalError(node, "Unexpected super property access $semantics.");
+ break;
}
- target = semantics.element;
+ registry.registerSendStructure(node,
+ isIncompatibleInvoke
+ ? new IncompatibleInvokeStructure(semantics, selector)
+ : new InvokeStructure(semantics, selector));
+ } else {
+ switch (semantics.kind) {
+ case AccessKind.SUPER_METHOD:
+ // TODO(johnniwinther): Method this should be registered as a
+ // closurization.
+ registry.registerStaticUse(semantics.element);
+ break;
+ case AccessKind.SUPER_FIELD:
+ case AccessKind.SUPER_FINAL_FIELD:
+ case AccessKind.SUPER_GETTER:
+ registry.registerStaticUse(semantics.element);
+ break;
+ case AccessKind.SUPER_SETTER:
+ case AccessKind.UNRESOLVED_SUPER:
+ // NoSuchMethod registered in [computeSuperSemantics].
+ break;
+ case AccessKind.INVALID:
+ // 'super' is not allowed.
+ break;
+ default:
+ internalError(node, "Unexpected super property access $semantics.");
+ break;
+ }
+ registry.registerSendStructure(node,
+ new GetStructure(semantics, selector));
}
+ target = semantics.element;
// TODO(johnniwinther): Remove these when all information goes through
// the [SendStructure].
@@ -1979,11 +2117,14 @@
Name name,
PrefixElement prefix) {
if ((ElementCategory.PREFIX & allowedCategory) == 0) {
- compiler.reportError(
+ ErroneousElement error = reportAndCreateErroneousElement(
node,
+ name.text,
MessageKind.PREFIX_AS_EXPRESSION,
- {'prefix': name});
- return const NoneResult();
+ {'prefix': name},
+ isError: true);
+ return handleErroneousAccess(
+ node, name, error, new StaticAccess.invalid(error));
}
if (prefix.isDeferred) {
// TODO(johnniwinther): Remove this when deferred access is detected
@@ -2062,8 +2203,7 @@
name.text,
MessageKind.THIS_PROPERTY, {},
isError: true);
- // TODO(johnniwinther): Support `this` as property as an [AccessSemantics].
- AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
+ AccessSemantics accessSemantics = new StaticAccess.invalid(error);
return handleErroneousAccess(node, name, error, accessSemantics);
}
@@ -2534,7 +2674,209 @@
return cls.computeType(compiler);
}
+ /// Handle index operations like `a[b] = c`, `a[b] += c`, and `a[b]++`.
+ ResolutionResult handleIndexSendSet(SendSet node) {
+ String operatorText = node.assignmentOperator.source;
+ Node receiver = node.receiver;
+ Node index = node.arguments.head;
+ visitExpression(receiver);
+ visitExpression(index);
+ if (node.isPrefix || node.isPostfix) {
+ // `a[b]++` or `++a[b]`.
+ IncDecOperator operator = IncDecOperator.parse(operatorText);
+ AccessSemantics semantics = new DynamicAccess.dynamicProperty(receiver);
+ Selector getterSelector = new Selector.index();
+ Selector setterSelector = new Selector.indexSet();
+ Selector operatorSelector =
+ new Selector.binaryOperator(operator.selectorName);
+
+ // TODO(johnniwinther): Remove these when selectors are only accessed
+ // through the send structure.
+ registry.setGetterSelectorInComplexSendSet(node, getterSelector);
+ registry.setSelector(node, setterSelector);
+ registry.setOperatorSelectorInComplexSendSet(node, operatorSelector);
+
+ registry.registerDynamicInvocation(
+ new UniverseSelector(getterSelector, null));
+ registry.registerDynamicInvocation(
+ new UniverseSelector(setterSelector, null));
+ registry.registerDynamicInvocation(
+ new UniverseSelector(operatorSelector, null));
+
+ SendStructure sendStructure = node.isPrefix
+ ? new IndexPrefixStructure(
+ semantics, operator, getterSelector, setterSelector)
+ : new IndexPostfixStructure(
+ semantics, operator, getterSelector, setterSelector);
+ registry.registerSendStructure(node, sendStructure);
+ return const NoneResult();
+ } else {
+ Node rhs = node.arguments.tail.head;
+ visitExpression(rhs);
+
+ AssignmentOperator operator = AssignmentOperator.parse(operatorText);
+ if (operator.kind == AssignmentOperatorKind.ASSIGN) {
+ // `a[b] = c`.
+ AccessSemantics semantics = new DynamicAccess.dynamicProperty(receiver);
+ Selector setterSelector = new Selector.indexSet();
+
+ // TODO(johnniwinther): Remove this when selectors are only accessed
+ // through the send structure.
+ registry.setSelector(node, setterSelector);
+ registry.registerDynamicInvocation(
+ new UniverseSelector(setterSelector, null));
+
+ SendStructure sendStructure =
+ new IndexSetStructure(semantics, setterSelector);
+ registry.registerSendStructure(node, sendStructure);
+ return const NoneResult();
+ } else {
+ // `a[b] += c`.
+ AccessSemantics semantics = new DynamicAccess.dynamicProperty(receiver);
+ Selector getterSelector = new Selector.index();
+ Selector setterSelector = new Selector.indexSet();
+ Selector operatorSelector =
+ new Selector.binaryOperator(operator.selectorName);
+
+ // TODO(johnniwinther): Remove these when selectors are only accessed
+ // through the send structure.
+ registry.setGetterSelectorInComplexSendSet(node, getterSelector);
+ registry.setSelector(node, setterSelector);
+ registry.setOperatorSelectorInComplexSendSet(node, operatorSelector);
+
+ registry.registerDynamicInvocation(
+ new UniverseSelector(getterSelector, null));
+ registry.registerDynamicInvocation(
+ new UniverseSelector(setterSelector, null));
+ registry.registerDynamicInvocation(
+ new UniverseSelector(operatorSelector, null));
+
+ SendStructure sendStructure = new CompoundIndexSetStructure(
+ semantics, operator, getterSelector, setterSelector);
+ registry.registerSendStructure(node, sendStructure);
+ return const NoneResult();
+ }
+ }
+ }
+
+ /// Handle super index operations like `super[a] = b`, `super[a] += b`, and
+ /// `super[a]++`.
+ // TODO(johnniwinther): Share code with [handleIndexSendSet].
+ ResolutionResult handleSuperIndexSendSet(SendSet node) {
+ String operatorText = node.assignmentOperator.source;
+ Node index = node.arguments.head;
+ visitExpression(index);
+ AccessSemantics semantics = checkSuperAccess(node);
+ if (node.isPrefix || node.isPostfix) {
+ // `super[a]++` or `++super[a]`.
+ IncDecOperator operator = IncDecOperator.parse(operatorText);
+ Selector getterSelector = new Selector.index();
+ Selector setterSelector = new Selector.indexSet();
+ Selector operatorSelector =
+ new Selector.binaryOperator(operator.selectorName);
+
+ // TODO(johnniwinther): Remove these when selectors are only accessed
+ // through the send structure.
+ registry.setGetterSelectorInComplexSendSet(node, getterSelector);
+ registry.setSelector(node, setterSelector);
+ registry.setOperatorSelectorInComplexSendSet(node, operatorSelector);
+
+ if (semantics == null) {
+ semantics = computeSuperAccessSemanticsForSelectors(
+ node, getterSelector, setterSelector);
+
+ registry.registerStaticInvocation(semantics.getter);
+ registry.registerStaticInvocation(semantics.setter);
+
+ // TODO(johnniwinther): Remove these when elements are only accessed
+ // through the send structure.
+ registry.useElement(node, semantics.setter);
+ registry.useElement(node.selector, semantics.getter);
+ }
+ registry.registerDynamicInvocation(
+ new UniverseSelector(operatorSelector, null));
+
+ SendStructure sendStructure = node.isPrefix
+ ? new IndexPrefixStructure(
+ semantics, operator, getterSelector, setterSelector)
+ : new IndexPostfixStructure(
+ semantics, operator, getterSelector, setterSelector);
+ registry.registerSendStructure(node, sendStructure);
+ return const NoneResult();
+ } else {
+ Node rhs = node.arguments.tail.head;
+ visitExpression(rhs);
+
+ AssignmentOperator operator = AssignmentOperator.parse(operatorText);
+ if (operator.kind == AssignmentOperatorKind.ASSIGN) {
+ // `super[a] = b`.
+ Selector setterSelector = new Selector.indexSet();
+ if (semantics == null) {
+ semantics =
+ computeSuperAccessSemanticsForSelector(node, setterSelector);
+
+ // TODO(johnniwinther): Remove these when elements are only accessed
+ // through the send structure.
+ registry.useElement(node, semantics.setter);
+ }
+
+ // TODO(johnniwinther): Remove this when selectors are only accessed
+ // through the send structure.
+ registry.setSelector(node, setterSelector);
+ registry.registerStaticInvocation(semantics.setter);
+
+ SendStructure sendStructure =
+ new IndexSetStructure(semantics, setterSelector);
+ registry.registerSendStructure(node, sendStructure);
+ return const NoneResult();
+ } else {
+ // `super[a] += b`.
+ Selector getterSelector = new Selector.index();
+ Selector setterSelector = new Selector.indexSet();
+ Selector operatorSelector =
+ new Selector.binaryOperator(operator.selectorName);
+ if (semantics == null) {
+ semantics = computeSuperAccessSemanticsForSelectors(
+ node, getterSelector, setterSelector);
+
+ registry.registerStaticInvocation(semantics.getter);
+ registry.registerStaticInvocation(semantics.setter);
+
+ // TODO(johnniwinther): Remove these when elements are only accessed
+ // through the send structure.
+ registry.useElement(node, semantics.setter);
+ registry.useElement(node.selector, semantics.getter);
+ }
+
+ // TODO(johnniwinther): Remove these when selectors are only accessed
+ // through the send structure.
+ registry.setGetterSelectorInComplexSendSet(node, getterSelector);
+ registry.setSelector(node, setterSelector);
+ registry.setOperatorSelectorInComplexSendSet(node, operatorSelector);
+
+ registry.registerDynamicInvocation(
+ new UniverseSelector(operatorSelector, null));
+
+ SendStructure sendStructure = new CompoundIndexSetStructure(
+ semantics, operator, getterSelector, setterSelector);
+ registry.registerSendStructure(node, sendStructure);
+ return const NoneResult();
+ }
+ }
+ }
+
ResolutionResult visitSendSet(SendSet node) {
+ if (node.isIndex) {
+ if (node.isSuperCall) {
+ return handleSuperIndexSendSet(node);
+ } else {
+ return handleIndexSendSet(node);
+ }
+ }
+ return oldVisitSendSet(node);
+ }
+
+ ResolutionResult oldVisitSendSet(SendSet node) {
bool oldSendIsMemberAccess = sendIsMemberAccess;
sendIsMemberAccess = node.isPropertyAccess || node.isCall;
ResolutionResult result = resolveSend(node);
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 1f3e943..36c4618 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -398,11 +398,13 @@
void registerIsCheck(DartType type) {
worldImpact.registerCheckedType(type);
backend.resolutionCallbacks.onIsCheck(type, this);
+ mapping.addRequiredType(type);
}
void registerAsCheck(DartType type) {
registerIsCheck(type);
backend.resolutionCallbacks.onAsCheck(type, this);
+ mapping.addRequiredType(type);
}
void registerClosure(LocalFunctionElement element) {
@@ -480,6 +482,7 @@
void registerInstantiatedType(InterfaceType type) {
world.registerInstantiatedType(type, this);
+ mapping.addRequiredType(type);
}
void registerAbstractClassInstantiation() {
@@ -492,6 +495,7 @@
void registerRequiredType(DartType type, Element enclosingElement) {
backend.registerRequiredType(type, enclosingElement);
+ mapping.addRequiredType(type);
}
void registerStringInterpolation() {
diff --git a/pkg/compiler/lib/src/resolution/semantic_visitor.dart b/pkg/compiler/lib/src/resolution/semantic_visitor.dart
index 3c265cc..d54b68a 100644
--- a/pkg/compiler/lib/src/resolution/semantic_visitor.dart
+++ b/pkg/compiler/lib/src/resolution/semantic_visitor.dart
@@ -141,6 +141,7 @@
/// Read of the [parameter].
///
/// For instance:
+ ///
/// m(parameter) => parameter;
///
R visitParameterGet(
@@ -151,6 +152,7 @@
/// Assignment of [rhs] to the [parameter].
///
/// For instance:
+ ///
/// m(parameter) {
/// parameter = rhs;
/// }
@@ -164,6 +166,7 @@
/// Assignment of [rhs] to the final [parameter].
///
/// For instance:
+ ///
/// m(final parameter) {
/// parameter = rhs;
/// }
@@ -177,6 +180,7 @@
/// Invocation of the [parameter] with [arguments].
///
/// For instance:
+ ///
/// m(parameter) {
/// parameter(null, 42);
/// }
@@ -191,6 +195,7 @@
/// Read of the local [variable].
///
/// For instance:
+ ///
/// m() {
/// var variable;
/// return variable;
@@ -204,6 +209,7 @@
/// Assignment of [rhs] to the local [variable].
///
/// For instance:
+ ///
/// m() {
/// var variable;
/// variable = rhs;
@@ -218,6 +224,7 @@
/// Assignment of [rhs] to the final local [variable].
///
/// For instance:
+ ///
/// m() {
/// final variable = null;
/// variable = rhs;
@@ -232,6 +239,7 @@
/// Invocation of the local variable [variable] with [arguments].
///
/// For instance:
+ ///
/// m() {
/// var variable;
/// variable(null, 42);
@@ -247,6 +255,7 @@
/// Closurization of the local [function].
///
/// For instance:
+ ///
/// m() {
/// o(a, b) {}
/// return o;
@@ -260,6 +269,7 @@
/// Assignment of [rhs] to the local [function].
///
/// For instance:
+ ///
/// m() {
/// o(a, b) {}
/// o = rhs;
@@ -274,6 +284,7 @@
/// Invocation of the local [function] with [arguments].
///
/// For instance:
+ ///
/// m() {
/// o(a, b) {}
/// return o(null, 42);
@@ -289,6 +300,7 @@
/// Invocation of the local [function] with incompatible [arguments].
///
/// For instance:
+ ///
/// m() {
/// o(a) {}
/// return o(null, 42);
@@ -303,7 +315,8 @@
/// Getter call on [receiver] of the property defined by [selector].
///
- /// For instance
+ /// For instance:
+ ///
/// m(receiver) => receiver.foo;
///
R visitDynamicPropertyGet(
@@ -315,7 +328,8 @@
/// Conditional (if not null) getter call on [receiver] of the property
/// defined by [selector].
///
- /// For instance
+ /// For instance:
+ ///
/// m(receiver) => receiver?.foo;
///
R visitIfNotNullDynamicPropertyGet(
@@ -327,7 +341,8 @@
/// Setter call on [receiver] with argument [rhs] of the property defined by
/// [selector].
///
- /// For instance
+ /// For instance:
+ ///
/// m(receiver) {
/// receiver.foo = rhs;
/// }
@@ -342,7 +357,8 @@
/// Conditional (if not null) setter call on [receiver] with argument [rhs] of
/// the property defined by [selector].
///
- /// For instance
+ /// For instance:
+ ///
/// m(receiver) {
/// receiver?.foo = rhs;
/// }
@@ -357,7 +373,8 @@
/// Invocation of the property defined by [selector] on [receiver] with
/// [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// m(receiver) {
/// receiver.foo(null, 42);
/// }
@@ -372,7 +389,8 @@
/// Conditinal invocation of the property defined by [selector] on [receiver]
/// with [arguments], if [receiver] is not null.
///
- /// For instance
+ /// For instance:
+ ///
/// m(receiver) {
/// receiver?.foo(null, 42);
/// }
@@ -386,7 +404,8 @@
/// Getter call on `this` of the property defined by [selector].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// m() => this.foo;
/// }
@@ -404,6 +423,9 @@
/// Setter call on `this` with argument [rhs] of the property defined by
/// [selector].
+ ///
+ /// For instance:
+ ///
/// class C {
/// m() { this.foo = rhs; }
/// }
@@ -423,7 +445,8 @@
/// Invocation of the property defined by [selector] on `this` with
/// [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// m() { this.foo(null, 42); }
/// }
@@ -443,7 +466,8 @@
/// Read of `this`.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// m() => this;
/// }
@@ -454,7 +478,8 @@
/// Invocation of `this` with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// m() => this(null, 42);
/// }
@@ -468,7 +493,8 @@
/// Read of the super [field].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// var foo;
/// }
@@ -483,7 +509,8 @@
/// Assignment of [rhs] to the super [field].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// var foo;
/// }
@@ -499,7 +526,8 @@
/// Assignment of [rhs] to the final static [field].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// final foo = null;
/// }
@@ -515,7 +543,8 @@
/// Invocation of the super [field] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// var foo;
/// }
@@ -532,7 +561,8 @@
/// Closurization of the super [method].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// foo(a, b) {}
/// }
@@ -547,7 +577,8 @@
/// Invocation of the super [method] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// foo(a, b) {}
/// }
@@ -564,7 +595,8 @@
/// Invocation of the super [method] with incompatible [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// foo(a, b) {}
/// }
@@ -581,7 +613,8 @@
/// Assignment of [rhs] to the super [method].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// foo(a, b) {}
/// }
@@ -597,7 +630,8 @@
/// Getter call to the super [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// get foo => null;
/// }
@@ -612,7 +646,8 @@
/// Getter call the super [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// set foo(_) {}
/// }
@@ -627,7 +662,8 @@
/// Setter call to the super [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// set foo(_) {}
/// }
@@ -643,7 +679,8 @@
/// Assignment of [rhs] to the super [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// get foo => null;
/// }
@@ -659,7 +696,8 @@
/// Invocation of the super [getter] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// get foo => null;
/// }
@@ -676,7 +714,8 @@
/// Invocation of the super [setter] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// set foo(_) {}
/// }
@@ -693,7 +732,8 @@
/// Invocation of a [expression] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// m() => (a, b){}(null, 42);
///
R visitExpressionInvoke(
@@ -705,7 +745,8 @@
/// Read of the static [field].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static var foo;
/// }
@@ -718,7 +759,8 @@
/// Assignment of [rhs] to the static [field].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static var foo;
/// }
@@ -732,7 +774,8 @@
/// Assignment of [rhs] to the final static [field].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static final foo;
/// }
@@ -746,7 +789,8 @@
/// Invocation of the static [field] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static var foo;
/// }
@@ -761,7 +805,8 @@
/// Closurization of the static [function].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static foo(a, b) {}
/// }
@@ -774,7 +819,8 @@
/// Invocation of the static [function] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static foo(a, b) {}
/// }
@@ -789,7 +835,8 @@
/// Invocation of the static [function] with incompatible [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static foo(a, b) {}
/// }
@@ -804,7 +851,8 @@
/// Assignment of [rhs] to the static [function].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static foo(a, b) {}
/// }
@@ -818,7 +866,8 @@
/// Getter call to the static [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static get foo => null;
/// }
@@ -831,7 +880,8 @@
/// Getter call the static [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static set foo(_) {}
/// }
@@ -844,7 +894,8 @@
/// Setter call to the static [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static set foo(_) {}
/// }
@@ -858,7 +909,8 @@
/// Assignment of [rhs] to the static [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static get foo => null;
/// }
@@ -872,7 +924,8 @@
/// Invocation of the static [getter] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static get foo => null;
/// }
@@ -887,7 +940,8 @@
/// Invocation of the static [setter] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static set foo(_) {}
/// }
@@ -902,7 +956,8 @@
/// Read of the top level [field].
///
- /// For instance
+ /// For instance:
+ ///
/// var foo;
/// m() => foo;
///
@@ -913,7 +968,8 @@
/// Assignment of [rhs] to the top level [field].
///
- /// For instance
+ /// For instance:
+ ///
/// var foo;
/// m() { foo = rhs; }
///
@@ -925,7 +981,8 @@
/// Assignment of [rhs] to the final top level [field].
///
- /// For instance
+ /// For instance:
+ ///
/// final foo = null;
/// m() { foo = rhs; }
///
@@ -937,7 +994,8 @@
/// Invocation of the top level [field] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// var foo;
/// m() { foo(null, 42); }
///
@@ -950,7 +1008,8 @@
/// Closurization of the top level [function].
///
- /// For instance
+ /// For instance:
+ ///
/// foo(a, b) {};
/// m() => foo;
///
@@ -961,7 +1020,8 @@
/// Invocation of the top level [function] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// foo(a, b) {};
/// m() { foo(null, 42); }
///
@@ -974,7 +1034,8 @@
/// Invocation of the top level [function] with incompatible [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static foo(a, b) {}
/// }
@@ -989,7 +1050,8 @@
/// Assignment of [rhs] to the top level [function].
///
- /// For instance
+ /// For instance:
+ ///
/// foo(a, b) {};
/// m() { foo = rhs; }
///
@@ -1001,7 +1063,8 @@
/// Getter call to the top level [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// get foo => null;
/// m() => foo;
///
@@ -1012,7 +1075,8 @@
/// Getter call the top level [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// set foo(_) {}
/// m() => foo;
///
@@ -1023,7 +1087,8 @@
/// Setter call to the top level [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// set foo(_) {}
/// m() { foo = rhs; }
///
@@ -1035,7 +1100,8 @@
/// Assignment of [rhs] to the top level [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// get foo => null;
/// m() { foo = rhs; }
///
@@ -1047,7 +1113,8 @@
/// Invocation of the top level [getter] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// get foo => null;
/// m() { foo(null, 42); }
///
@@ -1060,7 +1127,8 @@
/// Invocation of the top level [setter] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// set foo(_) {};
/// m() { foo(null, 42); }
///
@@ -1073,7 +1141,8 @@
/// Read of the type literal for class [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m() => C;
///
@@ -1084,7 +1153,8 @@
/// Invocation of the type literal for class [element] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m() => C(null, 42);
///
@@ -1097,7 +1167,8 @@
/// Assignment of [rhs] to the type literal for class [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m() { C = rhs; }
///
@@ -1109,7 +1180,8 @@
/// Read of the type literal for typedef [element].
///
- /// For instance
+ /// For instance:
+ ///
/// typedef F();
/// m() => F;
///
@@ -1120,7 +1192,8 @@
/// Invocation of the type literal for typedef [element] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// typedef F();
/// m() => F(null, 42);
///
@@ -1133,7 +1206,8 @@
/// Assignment of [rhs] to the type literal for typedef [element].
///
- /// For instance
+ /// For instance:
+ ///
/// typedef F();
/// m() { F = rhs; }
///
@@ -1145,7 +1219,8 @@
/// Read of the type literal for type variable [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class C<T> {
/// m() => T;
/// }
@@ -1158,7 +1233,8 @@
/// Invocation of the type literal for type variable [element] with
/// [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C<T> {
/// m() { T(null, 42); }
/// }
@@ -1172,7 +1248,8 @@
/// Assignment of [rhs] to the type literal for type variable [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class C<T> {
/// m() { T = rhs; }
/// }
@@ -1185,7 +1262,8 @@
/// Read of the type literal for `dynamic`.
///
- /// For instance
+ /// For instance:
+ ///
/// m() => dynamic;
///
R visitDynamicTypeLiteralGet(
@@ -1195,7 +1273,8 @@
/// Invocation of the type literal for `dynamic` with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// m() { dynamic(null, 42); }
///
R visitDynamicTypeLiteralInvoke(
@@ -1207,7 +1286,8 @@
/// Assignment of [rhs] to the type literal for `dynamic`.
///
- /// For instance
+ /// For instance:
+ ///
/// m() { dynamic = rhs; }
///
R visitDynamicTypeLiteralSet(
@@ -1219,6 +1299,7 @@
/// Call to `assert` with [expression] as the condition.
///
/// For instance:
+ ///
/// m() { assert(expression); }
///
R visitAssert(
@@ -1229,8 +1310,11 @@
/// Call to `assert` with the wrong number of [arguments].
///
/// For instance:
+ ///
/// m() { assert(); }
+ ///
/// or
+ ///
/// m() { assert(expression1, expression2); }
///
R errorInvalidAssert(
@@ -1243,6 +1327,7 @@
/// by [visitEquals] and index operations `a[b]` are handled by [visitIndex].
///
/// For instance:
+ ///
/// add(a, b) => a + b;
/// sub(a, b) => a - b;
/// mul(a, b) => a * b;
@@ -1259,6 +1344,7 @@
/// expressions using operator `==` are handled by [visitSuperEquals].
///
/// For instance:
+ ///
/// class B {
/// operator +(_) => null;
/// }
@@ -1275,7 +1361,8 @@
/// Binary operation on the unresolved super [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -1292,6 +1379,7 @@
/// Index expression `receiver[index]`.
///
/// For instance:
+ ///
/// lookup(a, b) => a[b];
///
R visitIndex(
@@ -1304,6 +1392,7 @@
/// the operation is defined by [operator].
///
/// For instance:
+ ///
/// lookup(a, b) => --a[b];
///
R visitIndexPrefix(
@@ -1317,6 +1406,7 @@
/// the operation is defined by [operator].
///
/// For instance:
+ ///
/// lookup(a, b) => a[b]++;
///
R visitIndexPostfix(
@@ -1330,6 +1420,7 @@
/// superclass by [function].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => null;
/// }
@@ -1346,6 +1437,7 @@
/// Index expression `super[index]` where 'operator []' is unresolved.
///
/// For instance:
+ ///
/// class B {}
/// class C extends B {
/// m(a) => super[a];
@@ -1363,6 +1455,7 @@
/// is defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => null;
/// operator []=(a, b) {}
@@ -1385,6 +1478,7 @@
/// is defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => null;
/// operator []=(a, b) {}
@@ -1406,6 +1500,7 @@
/// the operation is defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator []=(a, b) {}
/// }
@@ -1426,6 +1521,7 @@
/// the operation is defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator []=(a, b) {}
/// }
@@ -1446,6 +1542,7 @@
/// 'operator []=' is unresolved and the operation is defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => 42;
/// }
@@ -1466,6 +1563,7 @@
/// 'operator []=' is unresolved and the operation is defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => 42;
/// }
@@ -1486,6 +1584,7 @@
/// defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => 42;
/// }
@@ -1505,6 +1604,7 @@
/// defined by [operator].
///
/// For instance:
+ ///
/// class B {
/// operator [](_) => 42;
/// }
@@ -1522,6 +1622,7 @@
/// Binary expression `left == right`.
///
/// For instance:
+ ///
/// neq(a, b) => a != b;
///
R visitNotEquals(
@@ -1534,6 +1635,7 @@
/// superclass by [function].
///
/// For instance:
+ ///
/// class B {
/// operator +(_) => null;
/// }
@@ -1550,6 +1652,7 @@
/// Binary expression `left == right`.
///
/// For instance:
+ ///
/// eq(a, b) => a == b;
///
R visitEquals(
@@ -1562,6 +1665,7 @@
/// superclass by [function].
///
/// For instance:
+ ///
/// class B {
/// operator ==(_) => null;
/// }
@@ -1579,6 +1683,7 @@
/// definable operator.
///
/// For instance:
+ ///
/// neg(a, b) => -a;
/// comp(a, b) => ~a;
///
@@ -1592,6 +1697,7 @@
/// operator implemented on a superclass by [function].
///
/// For instance:
+ ///
/// class B {
/// operator -() => null;
/// }
@@ -1607,7 +1713,8 @@
/// Unary operation on the unresolved super [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -1623,6 +1730,7 @@
/// Unary expression `!expression`.
///
/// For instance:
+ ///
/// not(a) => !a;
///
R visitNot(
@@ -1633,6 +1741,7 @@
/// Index set expression `receiver[index] = rhs`.
///
/// For instance:
+ ///
/// m(receiver, index, rhs) => receiver[index] = rhs;
///
R visitIndexSet(
@@ -1646,6 +1755,7 @@
/// on a superclass by [function].
///
/// For instance:
+ ///
/// class B {
/// operator []=(a, b) {}
/// }
@@ -1663,7 +1773,8 @@
/// Index set expression `super[index] = rhs` where `operator []=` is
/// undefined.
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -1679,7 +1790,8 @@
/// If-null, ??, expression with operands [left] and [right].
///
- /// For instance
+ /// For instance:
+ ///
/// m() => left ?? right;
///
R visitIfNull(
@@ -1690,7 +1802,8 @@
/// Logical and, &&, expression with operands [left] and [right].
///
- /// For instance
+ /// For instance:
+ ///
/// m() => left && right;
///
R visitLogicalAnd(
@@ -1701,7 +1814,8 @@
/// Logical or, ||, expression with operands [left] and [right].
///
- /// For instance
+ /// For instance:
+ ///
/// m() => left || right;
///
R visitLogicalOr(
@@ -1712,7 +1826,8 @@
/// Is test of [expression] against [type].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m() => expression is C;
///
@@ -1724,7 +1839,8 @@
/// Is not test of [expression] against [type].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m() => expression is! C;
///
@@ -1736,7 +1852,8 @@
/// As cast of [expression] to [type].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m() => expression as C;
///
@@ -1751,6 +1868,7 @@
/// [setterSelector], respectively.
///
/// For instance:
+ ///
/// m(receiver, rhs) => receiver.foo += rhs;
///
R visitDynamicPropertyCompound(
@@ -1767,6 +1885,7 @@
/// [getterSelector] and [setterSelector], respectively.
///
/// For instance:
+ ///
/// m(receiver, rhs) => receiver?.foo += rhs;
///
R visitIfNotNullDynamicPropertyCompound(
@@ -1783,10 +1902,13 @@
/// [setterSelector], respectively.
///
/// For instance:
+ ///
/// class C {
/// m(rhs) => this.foo += rhs;
/// }
+ ///
/// or
+ ///
/// class C {
/// m(rhs) => foo += rhs;
/// }
@@ -1802,6 +1924,7 @@
/// Compound assignment expression of [rhs] with [operator] on a [parameter].
///
/// For instance:
+ ///
/// m(parameter, rhs) => parameter += rhs;
///
R visitParameterCompound(
@@ -1815,6 +1938,7 @@
/// [parameter].
///
/// For instance:
+ ///
/// m(final parameter, rhs) => parameter += rhs;
///
R visitFinalParameterCompound(
@@ -1828,6 +1952,7 @@
/// [variable].
///
/// For instance:
+ ///
/// m(rhs) {
/// var variable;
/// variable += rhs;
@@ -1844,6 +1969,7 @@
/// [variable].
///
/// For instance:
+ ///
/// m(rhs) {
/// final variable = 0;
/// variable += rhs;
@@ -1860,6 +1986,7 @@
/// [function].
///
/// For instance:
+ ///
/// m(rhs) {
/// function() {}
/// function += rhs;
@@ -1876,6 +2003,7 @@
/// [field].
///
/// For instance:
+ ///
/// class C {
/// static var field;
/// m(rhs) => field += rhs;
@@ -1892,6 +2020,7 @@
/// [field].
///
/// For instance:
+ ///
/// class C {
/// static final field = 0;
/// m(rhs) => field += rhs;
@@ -1908,6 +2037,7 @@
/// static [getter] and writing to a static [setter].
///
/// For instance:
+ ///
/// class C {
/// static get o => 0;
/// static set o(_) {}
@@ -1927,6 +2057,7 @@
/// [setter].
///
/// For instance:
+ ///
/// class C {
/// static o() {}
/// static set o(_) {}
@@ -1945,6 +2076,7 @@
/// [field].
///
/// For instance:
+ ///
/// var field;
/// m(rhs) => field += rhs;
///
@@ -1959,6 +2091,7 @@
/// level [field].
///
/// For instance:
+ ///
/// final field = 0;
/// m(rhs) => field += rhs;
///
@@ -1973,6 +2106,7 @@
/// top level [getter] and writing to a top level [setter].
///
/// For instance:
+ ///
/// get o => 0;
/// set o(_) {}
/// m(rhs) => o += rhs;
@@ -1990,6 +2124,7 @@
/// level [setter].
///
/// For instance:
+ ///
/// o() {}
/// set o(_) {}
/// m(rhs) => o += rhs;
@@ -2007,6 +2142,7 @@
/// unresolved setter.
///
/// For instance:
+ ///
/// o() {}
/// m(rhs) => o += rhs;
///
@@ -2021,6 +2157,7 @@
/// [field].
///
/// For instance:
+ ///
/// class B {
/// var field;
/// }
@@ -2039,6 +2176,7 @@
/// [field].
///
/// For instance:
+ ///
/// class B {
/// final field = 42;
/// }
@@ -2056,6 +2194,7 @@
/// Prefix expression with [operator] on a final super [field].
///
/// For instance:
+ ///
/// class B {
/// final field = 42;
/// }
@@ -2072,6 +2211,7 @@
/// Prefix expression with [operator] on an unresolved super property.
///
/// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -2087,6 +2227,7 @@
/// Postfix expression with [operator] on an unresolved super property.
///
/// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -2103,6 +2244,7 @@
/// super property.
///
/// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -2119,6 +2261,7 @@
/// Postfix expression with [operator] on a final super [field].
///
/// For instance:
+ ///
/// class B {
/// final field = 42;
/// }
@@ -2137,6 +2280,7 @@
/// [writtenField].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -2159,6 +2303,7 @@
/// super [getter] and writing to a super [setter].
///
/// For instance:
+ ///
/// class B {
/// get o => 0;
/// set o(_) {}
@@ -2180,6 +2325,7 @@
/// [setter].
///
/// For instance:
+ ///
/// class B {
/// o() {}
/// set o(_) {}
@@ -2200,6 +2346,7 @@
/// closurized super [method] and trying to invoke the non-existing setter.
///
/// For instance:
+ ///
/// class B {
/// o() {}
/// }
@@ -2217,7 +2364,8 @@
/// Compound assignment expression of [rhs] with [operator] reading from the
/// non-existing super getter and writing to a super [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// set o(_) {}
/// }
@@ -2236,7 +2384,8 @@
/// Compound assignment expression of [rhs] with [operator] reading from a
/// super [getter] and writing to the non-existing super setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// get o => 42;
/// }
@@ -2256,6 +2405,7 @@
/// super [field] and writing to a super [setter].
///
/// For instance:
+ ///
/// class A {
/// var o;
/// }
@@ -2278,6 +2428,7 @@
/// super [getter] and writing to a super [field].
///
/// For instance:
+ ///
/// class A {
/// var o;
/// }
@@ -2300,6 +2451,7 @@
/// for class [element].
///
/// For instance:
+ ///
/// class C {}
/// m(rhs) => C += rhs;
///
@@ -2314,6 +2466,7 @@
/// for typedef [element].
///
/// For instance:
+ ///
/// typedef F();
/// m(rhs) => F += rhs;
///
@@ -2328,6 +2481,7 @@
/// for type variable [element].
///
/// For instance:
+ ///
/// class C<T> {
/// m(rhs) => T += rhs;
/// }
@@ -2343,6 +2497,7 @@
/// literal for `dynamic`.
///
/// For instance:
+ ///
/// m(rhs) => dynamic += rhs;
///
R visitDynamicTypeLiteralCompound(
@@ -2357,6 +2512,7 @@
/// [getterSelector] and [setterSelector], respectively.
///
/// For instance:
+ ///
/// m(receiver, index, rhs) => receiver[index] += rhs;
///
R visitCompoundIndexSet(
@@ -2371,6 +2527,7 @@
/// operators of a super class defined by [getter] and [setter].
///
/// For instance:
+ ///
/// class B {
/// operator [](index) {}
/// operator [](index, value) {}
@@ -2392,7 +2549,8 @@
/// super class where the index getter is undefined and the index setter is
/// defined by [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -2412,7 +2570,8 @@
/// super class where the index getter is defined by [getter] but the index
/// setter is undefined.
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// operator [](index) => 42;
/// }
@@ -2432,7 +2591,8 @@
/// Compound index assignment of [rhs] with [operator] to [index] on a super
/// super class where the index getter and setter are undefined.
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// }
/// class C extends B {
@@ -2452,6 +2612,7 @@
/// respectively.
///
/// For instance:
+ ///
/// m(receiver) => ++receiver.foo;
///
R visitDynamicPropertyPrefix(
@@ -2467,6 +2628,7 @@
/// [setterSelector], respectively.
///
/// For instance:
+ ///
/// m(receiver) => ++receiver?.foo;
///
R visitIfNotNullDynamicPropertyPrefix(
@@ -2480,6 +2642,7 @@
/// Prefix expression with [operator] on a [parameter].
///
/// For instance:
+ ///
/// m(parameter) => ++parameter;
///
R visitParameterPrefix(
@@ -2491,6 +2654,7 @@
/// Prefix expression with [operator] on a final [parameter].
///
/// For instance:
+ ///
/// m(final parameter) => ++parameter;
///
R visitFinalParameterPrefix(
@@ -2502,9 +2666,10 @@
/// Prefix expression with [operator] on a local [variable].
///
/// For instance:
+ ///
/// m() {
- /// var variable;
- /// ++variable;
+ /// var variable;
+ /// ++variable;
/// }
///
R visitLocalVariablePrefix(
@@ -2516,9 +2681,10 @@
/// Prefix expression with [operator] on a final local [variable].
///
/// For instance:
+ ///
/// m() {
- /// final variable;
- /// ++variable;
+ /// final variable;
+ /// ++variable;
/// }
///
R visitFinalLocalVariablePrefix(
@@ -2530,9 +2696,10 @@
/// Prefix expression with [operator] on a local [function].
///
/// For instance:
+ ///
/// m() {
- /// function() {}
- /// ++function;
+ /// function() {}
+ /// ++function;
/// }
///
R visitLocalFunctionPrefix(
@@ -2547,10 +2714,13 @@
/// respectively.
///
/// For instance:
+ ///
/// class C {
/// m() => ++foo;
/// }
+ ///
/// or
+ ///
/// class C {
/// m() => ++this.foo;
/// }
@@ -2565,6 +2735,7 @@
/// Prefix expression with [operator] on a static [field].
///
/// For instance:
+ ///
/// class C {
/// static var field;
/// m() => ++field;
@@ -2579,6 +2750,7 @@
/// Prefix expression with [operator] on a final static [field].
///
/// For instance:
+ ///
/// class C {
/// static final field = 42;
/// m() => ++field;
@@ -2594,6 +2766,7 @@
/// writing to a static [setter].
///
/// For instance:
+ ///
/// class C {
/// static get o => 0;
/// static set o(_) {}
@@ -2612,6 +2785,7 @@
/// closurizing [method], and writing to a static [setter].
///
/// For instance:
+ ///
/// class C {
/// static o() {}
/// static set o(_) {}
@@ -2628,6 +2802,7 @@
/// Prefix expression with [operator] on a top level [field].
///
/// For instance:
+ ///
/// var field;
/// m() => ++field;
///
@@ -2640,6 +2815,7 @@
/// Prefix expression with [operator] on a final top level [field].
///
/// For instance:
+ ///
/// final field;
/// m() => ++field;
///
@@ -2653,6 +2829,7 @@
/// writing to a top level [setter].
///
/// For instance:
+ ///
/// get o => 0;
/// set o(_) {}
/// m() => ++o;
@@ -2668,6 +2845,7 @@
/// is, closurizing [method], and writing to a top level [setter].
///
/// For instance:
+ ///
/// o() {}
/// set o(_) {}
/// m() => ++o;
@@ -2682,6 +2860,7 @@
/// Prefix expression with [operator] on a super [field].
///
/// For instance:
+ ///
/// class B {
/// var field;
/// }
@@ -2699,6 +2878,7 @@
/// and writing to the different super field [writtenField].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -2720,6 +2900,7 @@
/// to a super [setter].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -2742,6 +2923,7 @@
/// writing to a super [setter].
///
/// For instance:
+ ///
/// class B {
/// get field => 0;
/// set field(_) {}
@@ -2761,6 +2943,7 @@
/// writing to a super [field].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -2782,6 +2965,7 @@
/// closurizing [method], and writing to a super [setter].
///
/// For instance:
+ ///
/// class B {
/// o() {}
/// set o(_) {}
@@ -2801,6 +2985,7 @@
/// closurizing [method], and writing to an unresolved super setter.
///
/// For instance:
+ ///
/// class B {
/// o() {}
/// set o(_) {}
@@ -2818,7 +3003,8 @@
/// Prefix expression with [operator] reading from an unresolved super getter
/// and writing to a super [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// set o(_) {}
/// }
@@ -2837,7 +3023,8 @@
/// Prefix expression with [operator] reading from a super [getter] and
/// writing to an unresolved super setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// get o => 42
/// }
@@ -2856,6 +3043,7 @@
/// Prefix expression with [operator] on a type literal for a class [element].
///
/// For instance:
+ ///
/// class C {}
/// m() => ++C;
///
@@ -2869,6 +3057,7 @@
/// [element].
///
/// For instance:
+ ///
/// typedef F();
/// m() => ++F;
///
@@ -2882,6 +3071,7 @@
/// [element].
///
/// For instance:
+ ///
/// class C<T> {
/// m() => ++T;
/// }
@@ -2895,6 +3085,7 @@
/// Prefix expression with [operator] on the type literal for `dynamic`.
///
/// For instance:
+ ///
/// m() => ++dynamic;
///
R visitDynamicTypeLiteralPrefix(
@@ -2908,6 +3099,7 @@
/// respectively.
///
/// For instance:
+ ///
/// m(receiver) => receiver.foo++;
///
R visitDynamicPropertyPostfix(
@@ -2923,6 +3115,7 @@
/// [setterSelector], respectively.
///
/// For instance:
+ ///
/// m(receiver) => receiver?.foo++;
///
R visitIfNotNullDynamicPropertyPostfix(
@@ -2936,6 +3129,7 @@
/// Postfix expression with [operator] on a [parameter].
///
/// For instance:
+ ///
/// m(parameter) => parameter++;
///
R visitParameterPostfix(
@@ -2947,6 +3141,7 @@
/// Postfix expression with [operator] on a final [parameter].
///
/// For instance:
+ ///
/// m(final parameter) => parameter++;
///
R visitFinalParameterPostfix(
@@ -2958,6 +3153,7 @@
/// Postfix expression with [operator] on a local [variable].
///
/// For instance:
+ ///
/// m() {
/// var variable;
/// variable++;
@@ -2972,6 +3168,7 @@
/// Postfix expression with [operator] on a final local [variable].
///
/// For instance:
+ ///
/// m() {
/// final variable;
/// variable++;
@@ -2986,6 +3183,7 @@
/// Postfix expression with [operator] on a local [function].
///
/// For instance:
+ ///
/// m() {
/// function() {}
/// function++;
@@ -3003,10 +3201,13 @@
/// respectively.
///
/// For instance:
+ ///
/// class C {
/// m() => foo++;
/// }
+ ///
/// or
+ ///
/// class C {
/// m() => this.foo++;
/// }
@@ -3021,6 +3222,7 @@
/// Postfix expression with [operator] on a static [field].
///
/// For instance:
+ ///
/// class C {
/// static var field;
/// m() => field++;
@@ -3035,6 +3237,7 @@
/// Postfix expression with [operator] on a final static [field].
///
/// For instance:
+ ///
/// class C {
/// static final field;
/// m() => field++;
@@ -3050,6 +3253,7 @@
/// writing to a static [setter].
///
/// For instance:
+ ///
/// class C {
/// static get o => 0;
/// static set o(_) {}
@@ -3068,6 +3272,7 @@
/// is, closurizing [method], and writing to a static [setter].
///
/// For instance:
+ ///
/// class C {
/// static o() {}
/// static set o(_) {}
@@ -3084,6 +3289,7 @@
/// Postfix expression with [operator] on a top level [field].
///
/// For instance:
+ ///
/// var field;
/// m() => field++;
///
@@ -3096,6 +3302,7 @@
/// Postfix expression with [operator] on a final top level [field].
///
/// For instance:
+ ///
/// final field = 42;
/// m() => field++;
///
@@ -3109,6 +3316,7 @@
/// writing to a top level [setter].
///
/// For instance:
+ ///
/// get o => 0;
/// set o(_) {}
/// m() => o++;
@@ -3124,6 +3332,7 @@
/// is, closurizing [method], and writing to a top level [setter].
///
/// For instance:
+ ///
/// o() {}
/// set o(_) {}
/// m() => o++;
@@ -3138,6 +3347,7 @@
/// Postfix expression with [operator] on a super [field].
///
/// For instance:
+ ///
/// class B {
/// var field;
/// }
@@ -3155,6 +3365,7 @@
/// [readField] and writing to the different super field [writtenField].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -3176,6 +3387,7 @@
/// writing to a super [setter].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -3198,6 +3410,7 @@
/// writing to a super [setter].
///
/// For instance:
+ ///
/// class B {
/// get field => 0;
/// set field(_) {}
@@ -3217,6 +3430,7 @@
/// writing to a super [field].
///
/// For instance:
+ ///
/// class A {
/// var field;
/// }
@@ -3238,6 +3452,7 @@
/// closurizing [method], and writing to a super [setter].
///
/// For instance:
+ ///
/// class B {
/// o() {}
/// set o(_) {}
@@ -3257,6 +3472,7 @@
/// closurizing [method], and writing to an unresolved super.
///
/// For instance:
+ ///
/// class B {
/// o() {}
/// set o(_) {}
@@ -3274,7 +3490,8 @@
/// Prefix expression with [operator] reading from an unresolved super getter
/// and writing to a super [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// set o(_) {}
/// }
@@ -3293,7 +3510,8 @@
/// Prefix expression with [operator] reading from a super [getter] and
/// writing to an unresolved super setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class B {
/// get o => 42
/// }
@@ -3313,6 +3531,7 @@
/// [element].
///
/// For instance:
+ ///
/// class C {}
/// m() => C++;
///
@@ -3326,6 +3545,7 @@
/// [element].
///
/// For instance:
+ ///
/// typedef F();
/// m() => F++;
///
@@ -3339,6 +3559,7 @@
/// [element].
///
/// For instance:
+ ///
/// class C<T> {
/// m() => T++;
/// }
@@ -3352,6 +3573,7 @@
/// Postfix expression with [operator] on the type literal for `dynamic`.
///
/// For instance:
+ ///
/// m() => dynamic++;
///
R visitDynamicTypeLiteralPostfix(
@@ -3362,7 +3584,8 @@
/// Read of the [constant].
///
- /// For instance
+ /// For instance:
+ ///
/// const c = c;
/// m() => c;
///
@@ -3373,7 +3596,8 @@
/// Invocation of the [constant] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// const c = null;
/// m() => c(null, 42);
///
@@ -3386,7 +3610,8 @@
/// Read of the unresolved [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m1() => unresolved;
/// m2() => prefix.unresolved;
@@ -3408,7 +3633,8 @@
/// Read of the unresolved super [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {}
/// class C {
/// m() => super.foo;
@@ -3421,7 +3647,8 @@
/// Assignment of [rhs] to the unresolved [element].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m1() => unresolved = 42;
/// m2() => prefix.unresolved = 42;
@@ -3444,7 +3671,8 @@
/// Invocation of the unresolved [element] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m1() => unresolved(null, 42);
/// m2() => prefix.unresolved(null, 42);
@@ -3468,7 +3696,8 @@
/// Invocation of the unresolved super [element] with [arguments].
///
- /// For instance
+ /// For instance:
+ ///
/// class B {}
/// class C extends B {
/// m() => super.foo();
@@ -3484,7 +3713,8 @@
/// Compound assignment of [rhs] with [operator] reading from the
/// non-existing static getter and writing to the static [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// set foo(_) {}
/// }
@@ -3501,7 +3731,8 @@
/// Compound assignment of [rhs] with [operator] reading from the
/// non-existing top level getter and writing to the top level [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// set foo(_) {}
/// m1() => foo += 42;
///
@@ -3516,7 +3747,8 @@
/// Compound assignment of [rhs] with [operator] reading from the static
/// [getter] and writing to the non-existing static setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// get foo => 42;
/// }
@@ -3533,7 +3765,8 @@
/// Compound assignment of [rhs] with [operator] reading from the top level
/// [getter] and writing to the non-existing top level setter.
///
- /// For instance
+ /// For instance:
+ ///
/// get foo => 42;
/// m1() => foo += 42;
///
@@ -3548,7 +3781,8 @@
/// Compound assignment of [rhs] with [operator] reading the closurized static
/// [method] and trying to invoke the non-existing setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// foo() {}
/// }
@@ -3563,7 +3797,8 @@
/// Compound assignment of [rhs] where both getter and setter are unresolved.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m1() => unresolved += 42;
/// m2() => prefix.unresolved += 42;
@@ -3588,7 +3823,8 @@
/// Prefix operation of [operator] reading from the non-existing static getter
/// and writing to the static [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// set foo(_) {}
/// }
@@ -3604,7 +3840,8 @@
/// Prefix operation of [operator] reading from the non-existing top level
/// getter and writing to the top level [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// set foo(_) {}
/// m1() => ++foo;
///
@@ -3618,7 +3855,8 @@
/// Prefix operation of [operator] reading from the static [getter] and
/// writing to the non-existing static setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// get foo => 42;
/// }
@@ -3634,7 +3872,8 @@
/// Postfix operation of [operator] reading from the top level [getter] and
/// writing to the non-existing top level setter.
///
- /// For instance
+ /// For instance:
+ ///
/// get foo => 42;
/// m1() => ++foo;
///
@@ -3648,7 +3887,8 @@
/// Prefix operation of [operator] reading the closurized static [method] and
/// trying to invoke the non-existing setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// foo() {}
/// }
@@ -3663,7 +3903,8 @@
/// Prefix operation of [operator] reading the closurized top level [method]
/// and trying to invoke the non-existing setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// foo() {}
/// }
@@ -3677,7 +3918,8 @@
/// Prefix operation where both getter and setter are unresolved.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m1() => ++unresolved;
/// m2() => ++prefix.unresolved;
@@ -3701,7 +3943,8 @@
/// Postfix operation of [operator] reading from the non-existing static
/// getter and writing to the static [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// set foo(_) {}
/// }
@@ -3717,7 +3960,8 @@
/// Postfix operation of [operator] reading from the non-existing top level
/// getter and writing to the top level [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// set foo(_) {}
/// m1() => foo++;
///
@@ -3731,7 +3975,8 @@
/// Postfix operation of [operator] reading from the static [getter] and
/// writing to the non-existing static setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// get foo => 42;
/// }
@@ -3747,7 +3992,8 @@
/// Postfix operation of [operator] reading from the top level [getter] and
/// writing to the non-existing top level setter.
///
- /// For instance
+ /// For instance:
+ ///
/// get foo => 42;
/// m1() => foo++;
///
@@ -3761,7 +4007,8 @@
/// Postfix operation of [operator] reading the closurized static [method] and
/// trying to invoke the non-existing setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// foo() {}
/// }
@@ -3776,7 +4023,8 @@
/// Postfix operation of [operator] reading the closurized top level [method]
/// and trying to invoke the non-existing setter.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// foo() {}
/// }
@@ -3790,7 +4038,8 @@
/// Postfix operation where both getter and setter are unresolved.
///
- /// For instance
+ /// For instance:
+ ///
/// class C {}
/// m1() => unresolved++;
/// m2() => prefix.unresolved++;
@@ -3829,11 +4078,12 @@
/// Const invocation of a [constant] constructor.
///
- /// For instance
- /// class C<T> {
- /// const C(a, b);
- /// }
- /// m() => const C<int>(true, 42);
+ /// For instance:
+ ///
+ /// class C<T> {
+ /// const C(a, b);
+ /// }
+ /// m() => const C<int>(true, 42);
///
R visitConstConstructorInvoke(
NewExpression node,
@@ -3842,8 +4092,9 @@
/// Const invocation of the `bool.fromEnvironment` constructor.
///
- /// For instance
- /// m() => const bool.fromEnvironment('foo', defaultValue: false);
+ /// For instance:
+ ///
+ /// m() => const bool.fromEnvironment('foo', defaultValue: false);
///
R visitBoolFromEnvironmentConstructorInvoke(
NewExpression node,
@@ -3852,8 +4103,9 @@
/// Const invocation of the `int.fromEnvironment` constructor.
///
- /// For instance
- /// m() => const int.fromEnvironment('foo', defaultValue: 42);
+ /// For instance:
+ ///
+ /// m() => const int.fromEnvironment('foo', defaultValue: 42);
///
R visitIntFromEnvironmentConstructorInvoke(
NewExpression node,
@@ -3862,8 +4114,9 @@
/// Const invocation of the `String.fromEnvironment` constructor.
///
- /// For instance
- /// m() => const String.fromEnvironment('foo', defaultValue: 'bar');
+ /// For instance:
+ ///
+ /// m() => const String.fromEnvironment('foo', defaultValue: 'bar');
///
R visitStringFromEnvironmentConstructorInvoke(
NewExpression node,
@@ -3872,11 +4125,12 @@
/// Invocation of a generative [constructor] on [type] with [arguments].
///
- /// For instance
- /// class C<T> {
- /// C(a, b);
- /// }
- /// m() => new C<int>(true, 42);
+ /// For instance:
+ ///
+ /// class C<T> {
+ /// C(a, b);
+ /// }
+ /// m() => new C<int>(true, 42);
///
/// where [type] is `C<int>`.
///
@@ -3891,12 +4145,13 @@
/// Invocation of a redirecting generative [constructor] on [type] with
/// [arguments].
///
- /// For instance
- /// class C<T> {
- /// C(a, b) : this._(b, a);
- /// C._(b, a);
- /// }
- /// m() => new C<int>(true, 42);
+ /// For instance:
+ ///
+ /// class C<T> {
+ /// C(a, b) : this._(b, a);
+ /// C._(b, a);
+ /// }
+ /// m() => new C<int>(true, 42);
///
/// where [type] is `C<int>`.
///
@@ -3910,12 +4165,13 @@
/// Invocation of a factory [constructor] on [type] with [arguments].
///
- /// For instance
- /// class C<T> {
- /// factory C(a, b) => new C<T>._(b, a);
- /// C._(b, a);
- /// }
- /// m() => new C<int>(true, 42);
+ /// For instance:
+ ///
+ /// class C<T> {
+ /// factory C(a, b) => new C<T>._(b, a);
+ /// C._(b, a);
+ /// }
+ /// m() => new C<int>(true, 42);
///
/// where [type] is `C<int>`.
///
@@ -3931,13 +4187,14 @@
/// [effectiveTarget] and [effectiveTargetType] are the constructor effective
/// invoked and its type, respectively.
///
- /// For instance
- /// class C<T> {
- /// factory C(a, b) = C<int>.a;
- /// factory C.a(a, b) = C<C<T>>.b;
- /// C.b(a, b);
- /// }
- /// m() => new C<double>(true, 42);
+ /// For instance:
+ ///
+ /// class C<T> {
+ /// factory C(a, b) = C<int>.a;
+ /// factory C.a(a, b) = C<C<T>>.b;
+ /// C.b(a, b);
+ /// }
+ /// m() => new C<double>(true, 42);
///
/// where [type] is `C<double>`, [effectiveTarget] is `C.b` and
/// [effectiveTargetType] is `C<C<int>>`.
@@ -3954,11 +4211,12 @@
/// Invocation of an unresolved [constructor] on [type] with [arguments].
///
- /// For instance
- /// class C<T> {
- /// C();
- /// }
- /// m() => new C<int>.unresolved(true, 42);
+ /// For instance:
+ ///
+ /// class C<T> {
+ /// C();
+ /// }
+ /// m() => new C<int>.unresolved(true, 42);
///
/// where [type] is `C<int>`.
///
@@ -3974,8 +4232,9 @@
/// Invocation of a constructor on an unresolved [type] with [arguments].
///
- /// For instance
- /// m() => new Unresolved(true, 42);
+ /// For instance:
+ ///
+ /// m() => new Unresolved(true, 42);
///
/// where [type] is the malformed type `Unresolved`.
///
@@ -3991,11 +4250,12 @@
/// Constant invocation of a non-constant constructor.
///
- /// For instance
- /// class C {
- /// C(a, b);
- /// }
- /// m() => const C(true, 42);
+ /// For instance:
+ ///
+ /// class C {
+ /// C(a, b);
+ /// }
+ /// m() => const C(true, 42);
///
R errorNonConstantConstructorInvoke(
NewExpression node,
@@ -4007,8 +4267,9 @@
/// Invocation of a constructor on an abstract [type] with [arguments].
///
- /// For instance
- /// m() => new Unresolved(true, 42);
+ /// For instance:
+ ///
+ /// m() => new Unresolved(true, 42);
///
/// where [type] is the malformed type `Unresolved`.
///
@@ -4024,13 +4285,14 @@
/// [effectiveTarget] and [effectiveTargetType] are the constructor effective
/// invoked and its type, respectively.
///
- /// For instance
- /// class C {
- /// factory C(a, b) = Unresolved;
- /// factory C.a(a, b) = C.unresolved;
- /// }
- /// m1() => new C(true, 42);
- /// m2() => new C.a(true, 42);
+ /// For instance:
+ ///
+ /// class C {
+ /// factory C(a, b) = Unresolved;
+ /// factory C.a(a, b) = C.unresolved;
+ /// }
+ /// m1() => new C(true, 42);
+ /// m2() => new C.a(true, 42);
///
R visitUnresolvedRedirectingFactoryConstructorInvoke(
NewExpression node,
@@ -4042,11 +4304,12 @@
/// Invocation of [constructor] on [type] with incompatible [arguments].
///
- /// For instance
- /// class C {
- /// C(a);
- /// }
- /// m() => C(true, 42);
+ /// For instance:
+ ///
+ /// class C {
+ /// C(a);
+ /// }
+ /// m() => C(true, 42);
///
R visitConstructorIncompatibleInvoke(
NewExpression node,
@@ -4056,12 +4319,231 @@
CallStructure callStructure,
A arg);
+ /// Read access of an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// import 'foo.dart' as p;
+ ///
+ /// m() => p;
+ ///
+ R errorInvalidGet(
+ Send node,
+ ErroneousElement error,
+ A arg);
+
+
+ /// Invocation of an invalid expression with [arguments].
+ ///
+ /// For instance:
+ ///
+ /// import 'foo.dart' as p;
+ ///
+ /// m() => p(null, 42);
+ ///
+ R errorInvalidInvoke(
+ Send node,
+ ErroneousElement error,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Assignment of [rhs] to an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// import 'foo.dart' as p;
+ ///
+ /// m() { p = 42; }
+ ///
+ R errorInvalidSet(
+ Send node,
+ ErroneousElement error,
+ Node rhs,
+ A arg);
+
+ /// Prefix operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// import 'foo.dart' as p;
+ ///
+ /// m() => ++p;
+ ///
+ R errorInvalidPrefix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ A arg);
+
+ /// Postfix operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// import 'foo.dart' as p;
+ ///
+ /// m() => p--;
+ ///
+ R errorInvalidPostfix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ A arg);
+
+ /// Compound assignment of [operator] with [rhs] on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// import 'foo.dart' as p;
+ ///
+ /// m() => p += 42;
+ ///
+ R errorInvalidCompound(
+ Send node,
+ ErroneousElement error,
+ AssignmentOperator operator,
+ Node rhs,
+ A arg);
+
+ /// Unary operation with [operator] on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => ~super;
+ /// }
+ ///
+ R errorInvalidUnary(
+ Send node,
+ UnaryOperator operator,
+ ErroneousElement error,
+ A arg);
+
+ /// Equals operation on an invalid left expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super == null;
+ /// }
+ ///
+ R errorInvalidEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ A arg);
+
+ /// Not equals operation on an invalid left expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super != null;
+ /// }
+ ///
+ R errorInvalidNotEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ A arg);
+
+ /// Binary operation with [operator] on an invalid left expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super + 0;
+ /// }
+ ///
+ R errorInvalidBinary(
+ Send node,
+ ErroneousElement error,
+ BinaryOperator operator,
+ Node right,
+ A arg);
+
+ /// Index operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super[0];
+ /// }
+ ///
+ R errorInvalidIndex(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ A arg);
+
+ /// Index set operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super[0] = 42;
+ /// }
+ ///
+ R errorInvalidIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ Node rhs,
+ A arg);
+
+ /// Compound index set operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super[0] += 42;
+ /// }
+ ///
+ R errorInvalidCompoundIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ AssignmentOperator operator,
+ Node rhs,
+ A arg);
+
+ /// Prefix index operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => --super[0];
+ /// }
+ ///
+ R errorInvalidIndexPrefix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ A arg);
+
+ /// Postfix index operation on an invalid expression.
+ ///
+ /// For instance:
+ ///
+ /// class C {
+ /// static m() => super[0]++;
+ /// }
+ ///
+ R errorInvalidIndexPostfix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ A arg);
+
/// Access of library through a deferred [prefix].
///
- /// For instance
- /// import 'lib.dart' deferred as prefix;
+ /// For instance:
///
- /// m() => prefix.foo;
+ /// import 'lib.dart' deferred as prefix;
+ ///
+ /// m() => prefix.foo;
///
/// This visit method is special in that it is called as a pre-step to calling
/// the visit method for the actual access. Therefore this method cannot
@@ -4083,7 +4565,8 @@
/// A declaration of a top level [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// get m => 42;
///
R visitTopLevelGetterDeclaration(
@@ -4094,7 +4577,8 @@
/// A declaration of a top level [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// set m(a) {}
///
R visitTopLevelSetterDeclaration(
@@ -4106,7 +4590,8 @@
/// A declaration of a top level [function].
///
- /// For instance
+ /// For instance:
+ ///
/// m(a) {}
///
R visitTopLevelFunctionDeclaration(
@@ -4118,7 +4603,8 @@
/// A declaration of a static [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static get m => 42;
/// }
@@ -4131,7 +4617,8 @@
/// A declaration of a static [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static set m(a) {}
/// }
@@ -4145,7 +4632,8 @@
/// A declaration of a static [function].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// static m(a) {}
/// }
@@ -4159,7 +4647,8 @@
/// A declaration of an abstract instance [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// abstract class C {
/// get m;
/// }
@@ -4171,7 +4660,8 @@
/// A declaration of an abstract instance [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// abstract class C {
/// set m(a);
/// }
@@ -4184,7 +4674,8 @@
/// A declaration of an abstract instance [method].
///
- /// For instance
+ /// For instance:
+ ///
/// abstract class C {
/// m(a);
/// }
@@ -4197,7 +4688,8 @@
/// A declaration of an instance [getter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// get m => 42;
/// }
@@ -4210,7 +4702,8 @@
/// A declaration of an instance [setter].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// set m(a) {}
/// }
@@ -4224,7 +4717,8 @@
/// A declaration of an instance [method].
///
- /// For instance
+ /// For instance:
+ ///
/// class C {
/// m(a) {}
/// }
@@ -4238,7 +4732,8 @@
/// A declaration of a local [function].
///
- /// For instance `local` in
+ /// For instance `local` in:
+ ///
/// m() {
/// local(a) {}
/// }
@@ -4252,7 +4747,8 @@
/// A declaration of a [closure].
///
- /// For instance `(a) {}` in
+ /// For instance `(a) {}` in:
+ ///
/// m() {
/// var closure = (a) {};
/// }
@@ -4267,7 +4763,8 @@
/// A declaration of the [index]th [parameter] in a constructor, setter,
/// method or function.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// m(a) {}
///
R visitParameterDeclaration(
@@ -4281,7 +4778,8 @@
/// method or function with the explicit [defaultValue]. If no default value
/// is declared, [defaultValue] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// m([a = 42]) {}
///
R visitOptionalParameterDeclaration(
@@ -4296,7 +4794,8 @@
/// with the explicit [defaultValue]. If no default value is declared,
/// [defaultValue] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// m({a: 42}) {}
///
R visitNamedParameterDeclaration(
@@ -4309,7 +4808,8 @@
/// A declaration of the [index]th [parameter] as an initializing formal in a
/// constructor.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// class C {
/// var a;
/// C(this.a);
@@ -4326,7 +4826,8 @@
/// formal in a constructor with the explicit [defaultValue]. If no default
/// value is declared, [defaultValue] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// class C {
/// var a;
/// C([this.a = 42]);
@@ -4344,7 +4845,8 @@
/// constructor with the explicit [defaultValue]. If no default value is
/// declared, [defaultValue] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// class C {
/// var a;
/// C({this.a: 42});
@@ -4360,7 +4862,8 @@
/// A declaration of a local [variable] with the explicit [initializer]. If
/// no initializer is declared, [initializer] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// m() {
/// var a = 42;
/// }
@@ -4374,7 +4877,8 @@
/// A declaration of a local constant [variable] initialized to [constant].
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// m() {
/// const a = 42;
/// }
@@ -4389,7 +4893,8 @@
/// A declaration of a top level [field] with the explicit [initializer].
/// If no initializer is declared, [initializer] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// var a = 42;
///
R visitTopLevelFieldDeclaration(
@@ -4401,7 +4906,8 @@
/// A declaration of a top level constant [field] initialized to [constant].
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// const a = 42;
///
R visitTopLevelConstantDeclaration(
@@ -4414,7 +4920,8 @@
/// A declaration of a static [field] with the explicit [initializer].
/// If no initializer is declared, [initializer] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// class C {
/// static var a = 42;
/// }
@@ -4428,7 +4935,8 @@
/// A declaration of a static constant [field] initialized to [constant].
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// class C {
/// static const a = 42;
/// }
@@ -4443,7 +4951,8 @@
/// A declaration of an instance [field] with the explicit [initializer].
/// If no initializer is declared, [initializer] is `null`.
///
- /// For instance `a` in
+ /// For instance `a` in:
+ ///
/// class C {
/// var a = 42;
/// }
@@ -4458,7 +4967,8 @@
/// A declaration of a generative [constructor] with the explicit constructor
/// [initializers].
///
- /// For instance `C` in
+ /// For instance `C` in:
+ ///
/// class C {
/// var a;
/// C(a) : this.a = a, super();
@@ -4477,7 +4987,8 @@
/// A declaration of a redirecting generative [constructor] with
/// [initializers] containing the redirecting constructor invocation.
///
- /// For instance `C` in
+ /// For instance `C` in:
+ ///
/// class C {
/// C() : this._();
/// C._();
@@ -4494,7 +5005,8 @@
/// A declaration of a factory [constructor].
///
- /// For instance `C` in
+ /// For instance `C` in:
+ ///
/// class C {
/// factory C(a) => null;
/// }
@@ -4510,7 +5022,8 @@
/// redirection target and its type is provided in [redirectionTarget] and
/// [redirectionType], respectively.
///
- /// For instance
+ /// For instance:
+ ///
/// class C<T> {
/// factory C() = C<int>.a;
/// factory C.a() = C<C<T>>.b;
@@ -4530,7 +5043,8 @@
/// An initializer of [field] with [initializer] as found in constructor
/// initializers.
///
- /// For instance `this.a = 42` in
+ /// For instance `this.a = 42` in:
+ ///
/// class C {
/// var a;
/// C() : this.a = 42;
@@ -4545,7 +5059,8 @@
/// An initializer of an unresolved field with [initializer] as found in
/// generative constructor initializers.
///
- /// For instance `this.a = 42` in
+ /// For instance `this.a = 42` in:
+ ///
/// class C {
/// C() : this.a = 42;
/// }
@@ -4559,7 +5074,8 @@
/// An super constructor invocation of [superConstructor] with [arguments] as
/// found in generative constructor initializers.
///
- /// For instance `super(42)` in
+ /// For instance `super(42)` in:
+ ///
/// class B {
/// B(a);
/// }
@@ -4578,7 +5094,8 @@
/// An implicit super constructor invocation of [superConstructor] from
/// generative constructor initializers.
///
- /// For instance `super(42)` in
+ /// For instance `super(42)` in:
+ ///
/// class B {
/// B();
/// }
@@ -4595,7 +5112,8 @@
/// An super constructor invocation of an unresolved with [arguments] as
/// found in generative constructor initializers.
///
- /// For instance `super(42)` in
+ /// For instance `super(42)` in:
+ ///
/// class B {
/// B(a);
/// }
@@ -4613,7 +5131,8 @@
/// An this constructor invocation of [thisConstructor] with [arguments] as
/// found in a redirecting generative constructors initializer.
///
- /// For instance `this._(42)` in
+ /// For instance `this._(42)` in:
+ ///
/// class C {
/// C() : this._(42);
/// C._(a);
@@ -4629,7 +5148,8 @@
/// An this constructor invocation of an unresolved constructor with
/// [arguments] as found in a redirecting generative constructors initializer.
///
- /// For instance `this._(42)` in
+ /// For instance `this._(42)` in:
+ ///
/// class C {
/// C() : this._(42);
/// }
diff --git a/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart b/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
index c1dfa54..ec45561 100644
--- a/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
+++ b/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
@@ -20,7 +20,9 @@
abstract class ErrorBulkMixin<R, A>
implements SemanticSendVisitor<R, A>, BulkHandle<R, A> {
- R bulkHandleError(Node node, A arg) {
+ // TODO(johnniwinther): Ensure that all error methods have an
+ // [ErroneousElement].
+ R bulkHandleError(Node node, ErroneousElement error, A arg) {
return bulkHandleNode(node, "Error expression `#` unhandled.", arg);
}
@@ -29,7 +31,7 @@
Send node,
NodeList arguments,
A arg) {
- return bulkHandleError(node, arg);
+ return bulkHandleError(node, null, arg);
}
@override
@@ -40,7 +42,7 @@
NodeList arguments,
CallStructure callStructure,
A arg) {
- return bulkHandleError(node, arg);
+ return bulkHandleError(node, null, arg);
}
@override
@@ -49,7 +51,7 @@
Operator operator,
Node expression,
A arg) {
- return bulkHandleError(node, arg);
+ return bulkHandleError(node, null, arg);
}
@override
@@ -59,7 +61,149 @@
Operator operator,
Node right,
A arg) {
- return bulkHandleError(node, arg);
+ return bulkHandleError(node, null, arg);
+ }
+
+ @override
+ R errorInvalidCompound(
+ Send node,
+ ErroneousElement error,
+ AssignmentOperator operator,
+ Node rhs,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidGet(
+ Send node,
+ ErroneousElement error,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidInvoke(
+ Send node,
+ ErroneousElement error,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidPostfix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidPrefix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidSet(
+ Send node,
+ ErroneousElement error,
+ Node rhs,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidUnary(
+ Send node,
+ UnaryOperator operator,
+ ErroneousElement error,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidNotEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidBinary(
+ Send node,
+ ErroneousElement error,
+ BinaryOperator operator,
+ Node right,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidIndex(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ Node rhs,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidCompoundIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ AssignmentOperator operator,
+ Node rhs,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidIndexPrefix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ A arg) {
+ return bulkHandleError(node, error, arg);
+ }
+
+ @override
+ R errorInvalidIndexPostfix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ A arg) {
+ return bulkHandleError(node, error, arg);
}
}
@@ -3534,6 +3678,161 @@
}
@override
+ R errorInvalidCompound(
+ Send node,
+ ErroneousElement error,
+ AssignmentOperator operator,
+ Node rhs,
+ A arg) {
+ apply(rhs, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidGet(
+ Send node,
+ ErroneousElement error,
+ A arg) {
+ return null;
+ }
+
+ @override
+ R errorInvalidInvoke(
+ Send node,
+ ErroneousElement error,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidPostfix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ A arg) {
+ return null;
+ }
+
+ @override
+ R errorInvalidPrefix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ A arg) {
+ return null;
+ }
+
+ @override
+ R errorInvalidSet(
+ Send node,
+ ErroneousElement error,
+ Node rhs,
+ A arg) {
+ apply(rhs, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidUnary(
+ Send node,
+ UnaryOperator operator,
+ ErroneousElement error,
+ A arg) {
+ return null;
+ }
+
+ @override
+ R errorInvalidEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ A arg) {
+ apply(right, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidNotEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ A arg) {
+ apply(right, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidBinary(
+ Send node,
+ ErroneousElement error,
+ BinaryOperator operator,
+ Node right,
+ A arg) {
+ apply(right, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidIndex(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ A arg) {
+ apply(index, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ Node rhs,
+ A arg) {
+ apply(index, arg);
+ apply(rhs, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidCompoundIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ AssignmentOperator operator,
+ Node rhs,
+ A arg) {
+ apply(index, arg);
+ apply(rhs, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidIndexPrefix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ A arg) {
+ apply(index, arg);
+ return null;
+ }
+
+ @override
+ R errorInvalidIndexPostfix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ A arg) {
+ apply(index, arg);
+ return null;
+ }
+
+ @override
R visitClassTypeLiteralSet(
SendSet node,
ConstantExpression constant,
diff --git a/pkg/compiler/lib/src/resolution/send_structure.dart b/pkg/compiler/lib/src/resolution/send_structure.dart
index a64c293..b5134a2 100644
--- a/pkg/compiler/lib/src/resolution/send_structure.dart
+++ b/pkg/compiler/lib/src/resolution/send_structure.dart
@@ -373,6 +373,13 @@
node.argumentsNode,
selector,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidInvoke(
+ node,
+ semantics.element,
+ node.argumentsNode,
+ selector,
+ arg);
case AccessKind.COMPOUND:
// This is not a valid case.
break;
@@ -590,6 +597,11 @@
node,
semantics.element,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidGet(
+ node,
+ semantics.element,
+ arg);
case AccessKind.COMPOUND:
// This is not a valid case.
break;
@@ -793,6 +805,12 @@
semantics.element,
node.arguments.single,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidSet(
+ node,
+ semantics.element,
+ node.arguments.single,
+ arg);
case AccessKind.COMPOUND:
// This is not a valid case.
break;
@@ -817,7 +835,7 @@
node,
node.receiver,
arg);
- default:
+ default:
// This is not a valid case.
break;
}
@@ -858,6 +876,12 @@
operator,
semantics.element,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidUnary(
+ node,
+ operator,
+ semantics.element,
+ arg);
default:
// This is not a valid case.
break;
@@ -913,6 +937,12 @@
semantics.element,
node.arguments.single,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidIndex(
+ node,
+ semantics.element,
+ node.arguments.single,
+ arg);
default:
// This is not a valid case.
break;
@@ -943,6 +973,12 @@
semantics.element,
node.arguments.single,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidEquals(
+ node,
+ semantics.element,
+ node.arguments.single,
+ arg);
default:
// This is not a valid case.
break;
@@ -975,6 +1011,12 @@
semantics.element,
node.arguments.single,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidNotEquals(
+ node,
+ semantics.element,
+ node.arguments.single,
+ arg);
default:
// This is not a valid case.
break;
@@ -1020,6 +1062,13 @@
operator,
node.arguments.single,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidBinary(
+ node,
+ semantics.element,
+ operator,
+ node.arguments.single,
+ arg);
default:
// This is not a valid case.
break;
@@ -1084,6 +1133,13 @@
node.arguments.first,
node.arguments.tail.head,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidIndexSet(
+ node,
+ semantics.element,
+ node.arguments.first,
+ node.arguments.tail.head,
+ arg);
default:
// This is not a valid case.
break;
@@ -1133,6 +1189,13 @@
node.arguments.single,
operator,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidIndexPrefix(
+ node,
+ semantics.element,
+ node.arguments.single,
+ operator,
+ arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
@@ -1212,6 +1275,13 @@
node.arguments.single,
operator,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidIndexPostfix(
+ node,
+ semantics.element,
+ node.arguments.single,
+ operator,
+ arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
@@ -1468,6 +1538,13 @@
operator,
node.arguments.single,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidCompound(
+ node,
+ semantics.element,
+ operator,
+ node.arguments.single,
+ arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
@@ -1633,6 +1710,14 @@
operator,
node.arguments.tail.head,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidCompoundIndexSet(
+ node,
+ semantics.element,
+ node.arguments.first,
+ operator,
+ node.arguments.tail.head,
+ arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
@@ -1871,6 +1956,12 @@
semantics.element,
operator,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidPrefix(
+ node,
+ semantics.element,
+ operator,
+ arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
@@ -2187,6 +2278,12 @@
semantics.element,
operator,
arg);
+ case AccessKind.INVALID:
+ return visitor.errorInvalidPostfix(
+ node,
+ semantics.element,
+ operator,
+ arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
diff --git a/pkg/compiler/lib/src/resolution/tree_elements.dart b/pkg/compiler/lib/src/resolution/tree_elements.dart
index 48c5430..e4dfb1e 100644
--- a/pkg/compiler/lib/src/resolution/tree_elements.dart
+++ b/pkg/compiler/lib/src/resolution/tree_elements.dart
@@ -12,8 +12,12 @@
/// [analyzedElement].
Iterable<Element> get allElements;
+ /// The set of types that this TreeElement depends on.
+ /// This includes instantiated types, types in is-checks and as-expressions
+ /// and in checked mode the types of all type-annotations.
+ Iterable<DartType> get requiredTypes;
+
void forEachConstantNode(f(Node n, ConstantExpression c));
- void forEachType(f(Node n, DartType t));
/// A set of additional dependencies. See [registerDependency] below.
Iterable<Element> get otherDependencies;
@@ -71,6 +75,9 @@
/// For example, elements that are used by a backend.
void registerDependency(Element element);
+ /// Register a dependency on [type].
+ void addRequiredType(DartType type);
+
/// Returns a list of nodes that potentially mutate [element] anywhere in its
/// scope.
List<Node> getPotentialMutations(VariableElement element);
@@ -112,6 +119,7 @@
Setlet<Element> _elements;
Setlet<Send> _asserts;
Maplet<Send, SendStructure> _sendStructureMap;
+ Setlet<DartType> _requiredTypes;
/// Map from nodes to the targets they define.
Map<Node, JumpTarget> _definedTargets;
@@ -175,9 +183,16 @@
DartType getType(Node node) => _types != null ? _types[node] : null;
- void forEachType(f(Node n, DartType t)) {
- if (_types != null) {
- _types.forEach(f);
+ void addRequiredType(DartType type) {
+ if (_requiredTypes == null) _requiredTypes = new Setlet<DartType>();
+ _requiredTypes.add(type);
+ }
+
+ Iterable<DartType> get requiredTypes {
+ if (_requiredTypes == null) {
+ return const <DartType>[];
+ } else {
+ return _requiredTypes;
}
}
diff --git a/pkg/compiler/lib/src/resolved_visitor.dart b/pkg/compiler/lib/src/resolved_visitor.dart
index dd60417..5eb6a13 100644
--- a/pkg/compiler/lib/src/resolved_visitor.dart
+++ b/pkg/compiler/lib/src/resolved_visitor.dart
@@ -327,10 +327,13 @@
Node node,
String message,
ResolvedKindVisitor<R> visitor) {
- return bulkHandleError(node, visitor);
+ return bulkHandleError(node, null, visitor);
}
- R bulkHandleError(Node node, ResolvedKindVisitor<R> visitor) {
+ R bulkHandleError(
+ Node node,
+ ErroneousElement error,
+ ResolvedKindVisitor<R> visitor) {
if (node.asSendSet() != null) {
return visitor.handleSendSet(node);
} else if (node.asNewExpression() != null) {
diff --git a/pkg/compiler/lib/src/scanner/listener.dart b/pkg/compiler/lib/src/scanner/listener.dart
index ef9b651..c3299a3 100644
--- a/pkg/compiler/lib/src/scanner/listener.dart
+++ b/pkg/compiler/lib/src/scanner/listener.dart
@@ -693,7 +693,8 @@
void reportError(Spannable spannable,
MessageKind messageKind,
[Map arguments = const {}]) {
- String message = messageKind.message(arguments, true).toString();
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+ String message = template.message(arguments, true).toString();
Token token;
if (spannable is Token) {
token = spannable;
@@ -1131,8 +1132,8 @@
} else {
reportFatalError(
token,
- MessageKind.MISSING_TOKEN_BEFORE_THIS.message(
- {'token': string}, true).toString());
+ MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
+ .message({'token': string}, true).toString());
}
return skipToEof(token);
}
@@ -2565,12 +2566,17 @@
Node parseNode(DiagnosticListener listener) {
if (cachedNode != null) return cachedNode;
- Metadata metadata = parse(listener,
- annotatedElement,
- declarationSite,
- (p) => p.parseMetadata(beginToken));
- cachedNode = metadata.expression;
- return cachedNode;
+ var metadata = parse(listener,
+ annotatedElement,
+ declarationSite,
+ (p) => p.parseMetadata(beginToken));
+ if (metadata is Metadata) {
+ cachedNode = metadata.expression;
+ return cachedNode;
+ } else {
+ assert (metadata is ErrorNode);
+ return metadata;
+ }
}
bool get hasNode => cachedNode != null;
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index 932864a..2269a9e 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -170,8 +170,8 @@
}
@override
- void report(Uri uri, int begin, int end, String message,
- api.Diagnostic kind) {
+ void report(var code, Uri uri, int begin, int end, String message,
+ api.Diagnostic kind) {
// TODO(ahe): Remove this when source map is handled differently.
if (identical(kind.name, 'source map')) return;
@@ -236,7 +236,7 @@
// TODO(johnniwinther): Remove this when no longer needed for the old compiler
// API.
void call(Uri uri, int begin, int end, String message, api.Diagnostic kind) {
- return report(uri, begin, end, message, kind);
+ return report(null, uri, begin, end, message, kind);
}
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 573bde0..435b4bb 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -492,7 +492,12 @@
"Cannot find value $local.");
}
}
- return directLocals[local];
+ HInstruction value = directLocals[local];
+ if (sourceInformation != null) {
+ value = new HRef(value, sourceInformation);
+ builder.add(value);
+ }
+ return value;
} else if (isStoredInClosureField(local)) {
ClosureFieldElement redirect = redirectionMapping[local];
HInstruction receiver = readLocal(closureData.closureElement);
@@ -518,9 +523,9 @@
assert(isUsedInTryOrGenerator(local));
HLocalValue localValue = getLocal(local);
HInstruction instruction = new HLocalGet(
- local, localValue, builder.backend.dynamicType);
+ local, localValue, builder.backend.dynamicType, sourceInformation);
builder.add(instruction);
- return instruction..sourceInformation = sourceInformation;
+ return instruction;
}
}
@@ -562,6 +567,10 @@
*/
void updateLocal(Local local, HInstruction value,
{SourceInformation sourceInformation}) {
+ if (value is HRef) {
+ HRef ref = value;
+ value = ref.value;
+ }
assert(!isStoredInClosureField(local));
if (isAccessedDirectly(local)) {
directLocals[local] = value;
@@ -1029,7 +1038,8 @@
with BaseImplementationOfCompoundsMixin,
SendResolverMixin,
SemanticSendResolvedMixin,
- NewBulkMixin
+ NewBulkMixin,
+ ErrorBulkMixin
implements SemanticSendVisitor {
final Compiler compiler;
final JavaScriptBackend backend;
@@ -1649,12 +1659,13 @@
backend.boolType));
},
visitThen: () {
- // TODO(johnniwinther): Add source information.
closeAndGotoExit(new HReturn(
graph.addConstantBool(false, compiler),
- null));
+ sourceInformationBuilder
+ .buildImplicitReturn(functionElement)));
},
- visitElse: null);
+ visitElse: null,
+ sourceInformation: sourceInformationBuilder.buildIf(function.body));
}
}
function.body.accept(this);
@@ -4898,7 +4909,13 @@
// The new object will now be referenced through the
// `setRuntimeTypeInfo` call. We therefore set the type of that
// instruction to be of the object's type.
- assert(stack.last is HInvokeStatic || stack.last == newObject);
+ assert(invariant(
+ CURRENT_ELEMENT_SPANNABLE,
+ stack.last is HInvokeStatic || stack.last == newObject,
+ message:
+ "Unexpected `stack.last`: Found ${stack.last}, "
+ "expected ${newObject} or an HInvokeStatic. "
+ "State: element=$element, rtiInputs=$rtiInputs, stack=$stack."));
stack.last.instructionType = newObject.instructionType;
return pop();
}
@@ -5620,7 +5637,8 @@
noSuchMethodTargetSymbolString(error, 'constructor'),
argumentNodes: node.send.arguments);
} else {
- Message message = error.messageKind.message(error.messageArguments);
+ MessageTemplate template = MessageTemplate.TEMPLATES[error.messageKind];
+ Message message = template.message(error.messageArguments);
generateRuntimeError(node.send, message.toString());
}
} else if (node.isConst) {
@@ -8257,6 +8275,12 @@
_) {
visitNode(node);
}
+
+ @override
+ void bulkHandleError(ast.Node node, ErroneousElement error, _) {
+ // TODO(johnniwinther): Use an uncatchable error when supported.
+ generateRuntimeError(node, error.message);
+ }
}
/**
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 6057d6f..998ed36 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1911,8 +1911,12 @@
registry.registerTypeConstant(element);
}
}
- push(backend.emitter.constantReference(constant)
- .withSourceInformation(sourceInformation));
+ js.Expression expression = backend.emitter.constantReference(constant);
+ if (!constant.isDummy) {
+ // TODO(johnniwinther): Support source information on synthetic constants.
+ expression = expression.withSourceInformation(sourceInformation);
+ }
+ push(expression);
}
visitConstant(HConstant node) {
@@ -2709,7 +2713,9 @@
js.Statement body = new js.Block.empty();
currentContainer = body;
if (node.isArgumentTypeCheck) {
- generateThrowWithHelper('iae', node.checkedInput);
+ generateThrowWithHelper('iae',
+ node.checkedInput,
+ sourceInformation: node.sourceInformation);
} else if (node.isReceiverTypeCheck) {
use(node.checkedInput);
js.Name methodName =
@@ -2859,4 +2865,9 @@
registry.registerStaticUse(helper);
return backend.emitter.staticFunctionAccess(helper);
}
+
+ @override
+ void visitRef(HRef node) {
+ visit(node.value);
+ }
}
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 0adc6e3..b23f32d 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -56,6 +56,7 @@
R visitPhi(HPhi node);
R visitRangeConversion(HRangeConversion node);
R visitReadModifyWrite(HReadModifyWrite node);
+ R visitRef(HRef node);
R visitReturn(HReturn node);
R visitShiftLeft(HShiftLeft node);
R visitShiftRight(HShiftRight node);
@@ -347,6 +348,7 @@
visitParameterValue(HParameterValue node) => visitLocalValue(node);
visitRangeConversion(HRangeConversion node) => visitCheck(node);
visitReadModifyWrite(HReadModifyWrite node) => visitInstruction(node);
+ visitRef(HRef node) => node.value.accept(this);
visitReturn(HReturn node) => visitControlFlow(node);
visitShiftLeft(HShiftLeft node) => visitBinaryBitOp(node);
visitShiftRight(HShiftRight node) => visitBinaryBitOp(node);
@@ -1307,6 +1309,32 @@
}
}
+/// A reference to a [HInstruction] that can hold its own source information.
+///
+/// This used for attaching source information to reads of locals.
+class HRef extends HInstruction {
+ HRef(HInstruction value, SourceInformation sourceInformation)
+ : super([value], value.instructionType) {
+ this.sourceInformation = sourceInformation;
+ }
+
+ HInstruction get value => inputs[0];
+
+ @override
+ HInstruction convertType(Compiler compiler, DartType type, int kind) {
+ HInstruction converted = value.convertType(compiler, type, kind);
+ if (converted == value) return this;
+ HTypeConversion conversion = converted;
+ conversion.inputs[0] = this;
+ return conversion;
+ }
+
+ @override
+ accept(HVisitor visitor) => visitor.visitRef(this);
+
+ String toString() => 'HRef(${value})';
+}
+
/**
* Late instructions are used after the main optimization phases. They capture
* codegen decisions just prior to generating JavaScript.
@@ -1714,8 +1742,11 @@
class HLocalGet extends HLocalAccess {
// No need to use GVN for a [HLocalGet], it is just a local
// access.
- HLocalGet(Local variable, HLocalValue local, TypeMask type)
- : super(variable, <HInstruction>[local], type);
+ HLocalGet(Local variable, HLocalValue local, TypeMask type,
+ SourceInformation sourceInformation)
+ : super(variable, <HInstruction>[local], type) {
+ this.sourceInformation = sourceInformation;
+ }
accept(HVisitor visitor) => visitor.visitLocalGet(this);
@@ -1795,6 +1826,8 @@
bool get isAllocation => nativeBehavior != null &&
nativeBehavior.isAllocation &&
!canBeNull();
+
+ String toString() => 'HForeignCode("${codeTemplate.source}",$inputs)';
}
class HForeignNew extends HForeign {
@@ -2396,8 +2429,10 @@
// (a && C.JSArray_methods).get$first(a)
//
- HInterceptor(HInstruction receiver, TypeMask type)
+ HInterceptor(HInstruction receiver,
+ TypeMask type)
: super(<HInstruction>[receiver], type) {
+ this.sourceInformation = receiver.sourceInformation;
sideEffects.clearAllSideEffects();
sideEffects.clearAllDependencies();
setUseGvn();
@@ -2717,7 +2752,14 @@
HInstruction get context => inputs[1];
HInstruction convertType(Compiler compiler, DartType type, int kind) {
- if (typeExpression == type) return this;
+ if (typeExpression == type) {
+ // Don't omit a boolean conversion (which doesn't allow `null`) unless
+ // this type conversion is already a boolean conversion.
+ if (kind != BOOLEAN_CONVERSION_CHECK ||
+ isBooleanConversionCheck) {
+ return this;
+ }
+ }
return super.convertType(compiler, type, kind);
}
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 0b50f8c..830c6c7 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -389,6 +389,10 @@
return buffer.toString();
}
+ String visitRef(HRef node) {
+ return 'Ref ${temporaryId(node.value)}';
+ }
+
String visitReturn(HReturn node) => "Return ${temporaryId(node.inputs[0])}";
String visitShiftLeft(HShiftLeft node) => handleInvokeBinary(node, '<<');
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index 8556472..2fb2d11 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -218,7 +218,8 @@
? instruction.selector
: null;
HTypeConversion converted = new HTypeConversion(
- null, kind, type, input, selector);
+ null, kind, type, input, selector)
+ ..sourceInformation = instruction.sourceInformation;
instruction.block.addBefore(instruction, converted);
input.replaceAllUsersDominatedBy(instruction, converted);
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index 1141665..6c864be 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -368,7 +368,29 @@
isEffectivelyConstant(node.value);
}
- Statement visitExpressionStatement(ExpressionStatement stmt) {
+ Statement visitExpressionStatement(ExpressionStatement inputNode) {
+ // Analyze chains of expression statements.
+ // To avoid deep recursion, [processExpressionStatement] returns a callback
+ // to invoke after its successor node has been processed.
+ // These callbacks are stored in a list and invoked in reverse at the end.
+ List<Function> stack = [];
+ Statement node = inputNode;
+ while (node is ExpressionStatement) {
+ stack.add(processExpressionStatement(node));
+ node = node.next;
+ }
+ Statement result = visitStatement(node);
+ for (Function fun in stack.reversed) {
+ result = fun(result);
+ }
+ return result;
+ }
+
+ /// Attempts to propagate an assignment in an expression statement.
+ ///
+ /// Returns a callback to be invoked after the sucessor statement has
+ /// been processed.
+ Function processExpressionStatement(ExpressionStatement stmt) {
Variable leftHand = getLeftHand(stmt.expression);
pushDominatingAssignment(leftHand);
if (isEffectivelyConstantAssignment(stmt.expression) &&
@@ -380,44 +402,50 @@
if (assign.variable.readCount == 1) {
// A single-use constant should always be propagated to its use site.
constantEnvironment[assign.variable] = assign.value;
- Statement next = visitStatement(stmt.next);
- popDominatingAssignment(leftHand);
- if (assign.variable.readCount > 0) {
- // The assignment could not be propagated into the successor, either
- // because it has an unsafe variable use (see [hasUnsafeVariableUse])
- // or because the use is outside the current try block, and we do
- // not currently support constant propagation out of a try block.
- constantEnvironment.remove(assign.variable);
- assign.value = visitExpression(assign.value);
- stmt.next = next;
- return stmt;
- } else {
- --assign.variable.writeCount;
- return next;
- }
+ return (Statement next) {
+ popDominatingAssignment(leftHand);
+ if (assign.variable.readCount > 0) {
+ // The assignment could not be propagated into the successor,
+ // either because it [hasUnsafeVariableUse] or because the
+ // use is outside the current try block, and we do not currently
+ // support constant propagation out of a try block.
+ constantEnvironment.remove(assign.variable);
+ assign.value = visitExpression(assign.value);
+ stmt.next = next;
+ return stmt;
+ } else {
+ --assign.variable.writeCount;
+ return next;
+ }
+ };
} else {
// With more than one use, we cannot propagate the constant.
// Visit the following statement without polluting [environment] so
// that any preceding non-constant assignments might still propagate.
- stmt.next = visitStatement(stmt.next);
- popDominatingAssignment(leftHand);
- assign.value = visitExpression(assign.value);
- return stmt;
+ return (Statement next) {
+ stmt.next = next;
+ popDominatingAssignment(leftHand);
+ assign.value = visitExpression(assign.value);
+ return stmt;
+ };
}
- }
- // Try to propagate the expression, and block previous impure expressions
- // until this has propagated.
- environment.add(stmt.expression);
- stmt.next = visitStatement(stmt.next);
- popDominatingAssignment(leftHand);
- if (!environment.isEmpty && environment.last == stmt.expression) {
- // Retain the expression statement.
- environment.removeLast();
- stmt.expression = visitExpression(stmt.expression);
- return stmt;
} else {
- // Expression was propagated into the successor.
- return stmt.next;
+ // Try to propagate the expression, and block previous impure expressions
+ // until this has propagated.
+ environment.add(stmt.expression);
+ return (Statement next) {
+ stmt.next = next;
+ popDominatingAssignment(leftHand);
+ if (!environment.isEmpty && environment.last == stmt.expression) {
+ // Retain the expression statement.
+ environment.removeLast();
+ stmt.expression = visitExpression(stmt.expression);
+ return stmt;
+ } else {
+ // Expression was propagated into the successor.
+ return stmt.next;
+ }
+ };
}
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index 73e4cfe..921e830 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -10,6 +10,8 @@
import '../util/util.dart' show CURRENT_ELEMENT_SPANNABLE;
import 'tree_ir_nodes.dart';
+typedef Statement NodeCallback(Statement next);
+
/**
* Builder translates from CPS-based IR to direct-style Tree.
*
@@ -42,7 +44,7 @@
* particular, intermediate values and blocks used for local control flow are
* still all named.
*/
-class Builder implements cps_ir.Visitor<Node> {
+class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
final dart2js.InternalErrorFunction internalError;
final Map<cps_ir.Primitive, Variable> primitive2variable =
@@ -109,6 +111,10 @@
return new VariableUse(getVariable(reference.definition));
}
+ Label getLabel(cps_ir.Continuation cont) {
+ return labels.putIfAbsent(cont, () => new Label());
+ }
+
Variable addFunctionParameter(cps_ir.Definition variable) {
if (variable is cps_ir.Parameter) {
return getVariable(variable);
@@ -130,7 +136,7 @@
node.parameters.map(addFunctionParameter).toList();
returnContinuation = node.returnContinuation;
phiTempVar = new Variable(node.element, null);
- Statement body = visit(node.body);
+ Statement body = translateExpression(node.body);
return new FunctionDefinition(node.element, parameters, body);
}
@@ -147,19 +153,6 @@
growable: false);
}
- Statement buildContinuationAssignment(
- cps_ir.Parameter parameter,
- Expression argument,
- Statement buildRest()) {
- Expression expr;
- if (parameter.hasAtLeastOneUse) {
- expr = new Assign(getVariable(parameter), argument);
- } else {
- expr = argument;
- }
- return new ExpressionStatement(expr, buildRest());
- }
-
/// Simultaneously assigns each argument to the corresponding parameter,
/// then continues at the statement created by [buildRest].
Statement buildPhiAssignments(
@@ -252,109 +245,134 @@
return first;
}
- visit(cps_ir.Node node) => node.accept(this);
+ visit(cps_ir.Node node) => throw 'Use translateXXX instead of visit';
- unexpectedNode(cps_ir.Node node) {
- internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
+ /// Translates a CPS expression into a tree statement.
+ ///
+ /// To avoid deep recursion, we traverse each basic blocks without
+ /// recursion.
+ ///
+ /// Non-tail expressions evaluate to a callback to be invoked once the
+ /// successor statement has been constructed. These callbacks are stored
+ /// in a stack until the block's tail expression has been translated.
+ Statement translateExpression(cps_ir.Expression node) {
+ List<NodeCallback> stack = <NodeCallback>[];
+ while (node is! cps_ir.TailExpression) {
+ stack.add(node.accept(this));
+ node = node.next;
+ }
+ Statement result = node.accept(this); // Translate the tail expression.
+ for (NodeCallback fun in stack.reversed) {
+ result = fun(result);
+ }
+ return result;
}
- Expression visitSetField(cps_ir.SetField node) {
- return new SetField(getVariableUse(node.object),
- node.field,
- getVariableUse(node.value));
- }
-
- Expression visitInterceptor(cps_ir.Interceptor node) {
- return new Interceptor(getVariableUse(node.input), node.interceptedClasses);
+ /// Translates a CPS primitive to a tree expression.
+ ///
+ /// This simply calls the visit method for the primitive.
+ Expression translatePrimitive(cps_ir.Primitive prim) {
+ return prim.accept(this);
}
- Expression visitCreateInstance(cps_ir.CreateInstance node) {
- return new CreateInstance(
- node.classElement,
- translateArguments(node.arguments),
- translateArguments(node.typeInformation),
- node.sourceInformation);
+ /// Translates a condition to a tree expression.
+ Expression translateCondition(cps_ir.Condition condition) {
+ cps_ir.IsTrue isTrue = condition;
+ return getVariableUse(isTrue.value);
}
- Expression visitGetField(cps_ir.GetField node) {
- return new GetField(getVariableUse(node.object), node.field,
- objectIsNotNull: node.objectIsNotNull);
- }
+ /************************ INTERIOR EXPRESSIONS ************************/
+ //
+ // Visit methods for interior expressions must return a function:
+ //
+ // (Statement next) => <result statement>
+ //
- Expression visitCreateBox(cps_ir.CreateBox node) {
- return new CreateBox();
- }
-
- visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
- return new CreateInvocationMirror(
- node.selector,
- translateArguments(node.arguments));
- }
-
- // Executable definitions are not visited directly. They have 'build'
- // functions as entry points.
- visitFunctionDefinition(cps_ir.FunctionDefinition node) {
- return unexpectedNode(node);
- }
-
- Statement visitLetPrim(cps_ir.LetPrim node) {
+ NodeCallback visitLetPrim(cps_ir.LetPrim node) => (Statement next) {
Variable variable = getVariable(node.primitive);
- Expression value = visit(node.primitive);
+ Expression value = translatePrimitive(node.primitive);
if (node.primitive.hasAtLeastOneUse) {
- return Assign.makeStatement(variable, value, visit(node.body));
+ return Assign.makeStatement(variable, value, next);
} else {
- return new ExpressionStatement(value, visit(node.body));
+ return new ExpressionStatement(value, next);
}
- }
+ };
- Statement visitLetCont(cps_ir.LetCont node) {
- // Introduce labels for continuations that need them.
+ // Continuations are bound at the same level, but they have to be
+ // translated as if nested. This is because the body can invoke any
+ // of them from anywhere, so it must be nested inside all of them.
+ //
+ // The continuation bodies are not always translated directly here because
+ // they may have been already translated:
+ // * For singly-used continuations, the continuation's body is
+ // translated at the site of the continuation invocation.
+ // * For recursive continuations, there is a single non-recursive
+ // invocation. The continuation's body is translated at the site
+ // of the non-recursive continuation invocation.
+ // See [visitInvokeContinuation] for the implementation.
+ NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) {
for (cps_ir.Continuation continuation in node.continuations) {
- if (continuation.hasMultipleUses || continuation.isRecursive) {
- labels[continuation] = new Label();
- }
- }
- Statement body = visit(node.body);
- // Continuations are bound at the same level, but they have to be
- // translated as if nested. This is because the body can invoke any
- // of them from anywhere, so it must be nested inside all of them.
- //
- // The continuation bodies are not always translated directly here because
- // they may have been already translated:
- // * For singly-used continuations, the continuation's body is
- // translated at the site of the continuation invocation.
- // * For recursive continuations, there is a single non-recursive
- // invocation. The continuation's body is translated at the site
- // of the non-recursive continuation invocation.
- // See visitInvokeContinuation for the implementation.
- Statement current = body;
- for (cps_ir.Continuation continuation in node.continuations.reversed) {
+ // This happens after the body of the LetCont has been translated.
+ // Labels are created on-demand if the continuation could not be inlined,
+ // so the existence of the label indicates if a labeled statement should
+ // be emitted.
Label label = labels[continuation];
if (label != null && !continuation.isRecursive) {
- current =
- new LabeledStatement(label, current, visit(continuation.body));
+ // Recursively build the body. We only do this for join continuations,
+ // so we should not risk overly deep recursion.
+ next = new LabeledStatement(
+ label,
+ next,
+ translateExpression(continuation.body));
}
}
- return current;
- }
+ return next;
+ };
- Statement visitLetHandler(cps_ir.LetHandler node) {
- Statement tryBody = visit(node.body);
+ NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) {
List<Variable> catchParameters =
node.handler.parameters.map(getVariable).toList();
- Statement catchBody = visit(node.handler.body);
- return new Try(tryBody, catchParameters, catchBody);
+ Statement catchBody = translateExpression(node.handler.body);
+ return new Try(next, catchParameters, catchBody);
+ };
+
+ NodeCallback visitLetMutable(cps_ir.LetMutable node) {
+ Variable variable = addMutableVariable(node.variable);
+ Expression value = getVariableUse(node.value);
+ return (Statement next) => Assign.makeStatement(variable, value, next);
}
- Statement visitInvokeStatic(cps_ir.InvokeStatic node) {
- // Calls are translated to direct style.
+
+ /************************ CALL EXPRESSIONS ************************/
+ //
+ // Visit methods for call expressions must return a function:
+ //
+ // (Statement next) => <result statement>
+ //
+ // The result statement must include an assignment to the continuation
+ // parameter, if the parameter is used.
+ //
+
+ NodeCallback makeCallExpression(cps_ir.CallExpression call,
+ Expression expression) {
+ return (Statement next) {
+ cps_ir.Parameter result = call.continuation.definition.parameters.single;
+ if (result.hasAtLeastOneUse) {
+ return Assign.makeStatement(getVariable(result), expression, next);
+ } else {
+ return new ExpressionStatement(expression, next);
+ }
+ };
+ }
+
+ NodeCallback visitInvokeStatic(cps_ir.InvokeStatic node) {
List<Expression> arguments = translateArguments(node.arguments);
Expression invoke = new InvokeStatic(node.target, node.selector, arguments,
node.sourceInformation);
- return continueWithExpression(node.continuation, invoke);
+ return makeCallExpression(node, invoke);
}
- Statement visitInvokeMethod(cps_ir.InvokeMethod node) {
+ NodeCallback visitInvokeMethod(cps_ir.InvokeMethod node) {
InvokeMethod invoke = new InvokeMethod(
getVariableUse(node.receiver),
node.selector,
@@ -362,17 +380,71 @@
translateArguments(node.arguments),
node.sourceInformation);
invoke.receiverIsNotNull = node.receiverIsNotNull;
- return continueWithExpression(node.continuation, invoke);
+ return makeCallExpression(node, invoke);
}
- Statement visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
+ NodeCallback visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
Expression receiver = getVariableUse(node.receiver);
List<Expression> arguments = translateArguments(node.arguments);
Expression invoke = new InvokeMethodDirectly(receiver, node.target,
node.selector, arguments, node.sourceInformation);
- return continueWithExpression(node.continuation, invoke);
+ return makeCallExpression(node, invoke);
}
+ NodeCallback visitTypeCast(cps_ir.TypeCast node) {
+ Expression value = getVariableUse(node.value);
+ List<Expression> typeArgs = translateArguments(node.typeArguments);
+ Expression expression =
+ new TypeOperator(value, node.type, typeArgs, isTypeTest: false);
+ return makeCallExpression(node, expression);
+ }
+
+ NodeCallback visitInvokeConstructor(cps_ir.InvokeConstructor node) {
+ List<Expression> arguments = translateArguments(node.arguments);
+ Expression invoke = new InvokeConstructor(
+ node.type,
+ node.target,
+ node.selector,
+ arguments,
+ node.sourceInformation);
+ return makeCallExpression(node, invoke);
+ }
+
+ NodeCallback visitForeignCode(cps_ir.ForeignCode node) {
+ if (node.codeTemplate.isExpression) {
+ Expression foreignCode = new ForeignExpression(
+ node.codeTemplate,
+ node.type,
+ node.arguments.map(getVariableUse).toList(growable: false),
+ node.nativeBehavior,
+ node.dependency);
+ return makeCallExpression(node, foreignCode);
+ } else {
+ return (Statement next) {
+ assert(next is Unreachable); // We are not using the `next` statement.
+ return new ForeignStatement(
+ node.codeTemplate,
+ node.type,
+ node.arguments.map(getVariableUse).toList(growable: false),
+ node.nativeBehavior,
+ node.dependency);
+ };
+ }
+ }
+
+ NodeCallback visitGetLazyStatic(cps_ir.GetLazyStatic node) {
+ // In the tree IR, GetStatic handles lazy fields because we do not need
+ // as fine-grained control over side effects.
+ GetStatic value = new GetStatic(node.element, node.sourceInformation);
+ return makeCallExpression(node, value);
+ }
+
+
+ /************************** TAIL EXPRESSIONS **************************/
+ //
+ // Visit methods for tail expressions must return a statement directly
+ // (not a function like interior and call expressions).
+
Statement visitThrow(cps_ir.Throw node) {
Expression value = getVariableUse(node.value);
return new Throw(value);
@@ -386,66 +458,6 @@
return new Unreachable();
}
- Expression visitNonTailThrow(cps_ir.NonTailThrow node) {
- return unexpectedNode(node);
- }
-
- Statement continueWithExpression(cps_ir.Reference continuation,
- Expression expression) {
- cps_ir.Continuation cont = continuation.definition;
- if (cont == returnContinuation) {
- return new Return(expression);
- } else {
- assert(cont.parameters.length == 1);
- Function nextBuilder = cont.hasExactlyOneUse ?
- () => visit(cont.body) : () => new Break(labels[cont]);
- return buildContinuationAssignment(cont.parameters.single, expression,
- nextBuilder);
- }
- }
-
- Statement visitLetMutable(cps_ir.LetMutable node) {
- Variable variable = addMutableVariable(node.variable);
- Expression value = getVariableUse(node.value);
- Statement body = visit(node.body);
- return Assign.makeStatement(variable, value, body);
- }
-
- Expression visitGetMutable(cps_ir.GetMutable node) {
- return getMutableVariableUse(node.variable);
- }
-
- Expression visitSetMutable(cps_ir.SetMutable node) {
- Variable variable = getMutableVariable(node.variable.definition);
- Expression value = getVariableUse(node.value);
- return new Assign(variable, value);
- }
-
- Statement visitTypeCast(cps_ir.TypeCast node) {
- Expression value = getVariableUse(node.value);
- List<Expression> typeArgs = translateArguments(node.typeArguments);
- Expression expression =
- new TypeOperator(value, node.type, typeArgs, isTypeTest: false);
- return continueWithExpression(node.continuation, expression);
- }
-
- Expression visitTypeTest(cps_ir.TypeTest node) {
- Expression value = getVariableUse(node.value);
- List<Expression> typeArgs = translateArguments(node.typeArguments);
- return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
- }
-
- Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) {
- List<Expression> arguments = translateArguments(node.arguments);
- Expression invoke = new InvokeConstructor(
- node.type,
- node.target,
- node.selector,
- arguments,
- node.sourceInformation);
- return continueWithExpression(node.continuation, invoke);
- }
-
Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) {
// Invocations of the return continuation are translated to returns.
// Other continuation invocations are replaced with assignments of the
@@ -474,35 +486,85 @@
// - Translate the recursive invocations to Continue.
if (cont.isRecursive) {
return node.isRecursive
- ? new Continue(labels[cont])
- : new WhileTrue(labels[cont], visit(cont.body));
+ ? new Continue(getLabel(cont))
+ : new WhileTrue(getLabel(cont),
+ translateExpression(cont.body));
} else {
- if (cont.hasExactlyOneUse) {
- if (!node.isEscapingTry) {
- return visit(cont.body);
- }
- labels[cont] = new Label();
- }
- return new Break(labels[cont]);
+ return cont.hasExactlyOneUse && !node.isEscapingTry
+ ? translateExpression(cont.body)
+ : new Break(getLabel(cont));
}
});
}
}
Statement visitBranch(cps_ir.Branch node) {
- Expression condition = visit(node.condition);
+ Expression condition = translateCondition(node.condition);
Statement thenStatement, elseStatement;
cps_ir.Continuation cont = node.trueContinuation.definition;
assert(cont.parameters.isEmpty);
- thenStatement =
- cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]);
+ thenStatement = cont.hasExactlyOneUse
+ ? translateExpression(cont.body)
+ : new Break(labels[cont]);
cont = node.falseContinuation.definition;
assert(cont.parameters.isEmpty);
- elseStatement =
- cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]);
+ elseStatement = cont.hasExactlyOneUse
+ ? translateExpression(cont.body)
+ : new Break(labels[cont]);
return new If(condition, thenStatement, elseStatement);
}
+
+ /************************** PRIMITIVES **************************/
+ //
+ // Visit methods for primitives must return an expression.
+ //
+
+ Expression visitSetField(cps_ir.SetField node) {
+ return new SetField(getVariableUse(node.object),
+ node.field,
+ getVariableUse(node.value));
+ }
+
+ Expression visitInterceptor(cps_ir.Interceptor node) {
+ return new Interceptor(getVariableUse(node.input),
+ node.interceptedClasses,
+ node.sourceInformation);
+ }
+
+ Expression visitCreateInstance(cps_ir.CreateInstance node) {
+ return new CreateInstance(
+ node.classElement,
+ translateArguments(node.arguments),
+ translateArguments(node.typeInformation),
+ node.sourceInformation);
+ }
+
+ Expression visitGetField(cps_ir.GetField node) {
+ return new GetField(getVariableUse(node.object), node.field,
+ objectIsNotNull: node.objectIsNotNull);
+ }
+
+ Expression visitCreateBox(cps_ir.CreateBox node) {
+ return new CreateBox();
+ }
+
+ Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
+ return new CreateInvocationMirror(
+ node.selector,
+ translateArguments(node.arguments));
+ }
+
+ Expression visitGetMutable(cps_ir.GetMutable node) {
+ return getMutableVariableUse(node.variable);
+ }
+
+ Expression visitSetMutable(cps_ir.SetMutable node) {
+ Variable variable = getMutableVariable(node.variable.definition);
+ Expression value = getVariableUse(node.value);
+ return new Assign(variable, value);
+ }
+
Expression visitConstant(cps_ir.Constant node) {
return new Constant(node.value, sourceInformation: node.sourceInformation);
}
@@ -533,28 +595,6 @@
return new FunctionExpression(def);
}
- visitParameter(cps_ir.Parameter node) {
- // Continuation parameters are not visited (continuations themselves are
- // not visited yet).
- unexpectedNode(node);
- }
-
- visitContinuation(cps_ir.Continuation node) {
- // Until continuations with multiple uses are supported, they are not
- // visited.
- unexpectedNode(node);
- }
-
- visitMutableVariable(cps_ir.MutableVariable node) {
- // These occur as parameters or bound by LetMutable. They are not visited
- // directly.
- unexpectedNode(node);
- }
-
- Expression visitIsTrue(cps_ir.IsTrue node) {
- return getVariableUse(node.value);
- }
-
Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
return new ReifyRuntimeType(
getVariableUse(node.value), node.sourceInformation);
@@ -567,22 +607,20 @@
node.sourceInformation);
}
- @override
- Node visitTypeExpression(cps_ir.TypeExpression node) {
+ Expression visitTypeExpression(cps_ir.TypeExpression node) {
return new TypeExpression(
node.dartType,
node.arguments.map(getVariableUse).toList());
}
- Expression visitGetStatic(cps_ir.GetStatic node) {
- return new GetStatic(node.element, node.sourceInformation);
+ Expression visitTypeTest(cps_ir.TypeTest node) {
+ Expression value = getVariableUse(node.value);
+ List<Expression> typeArgs = translateArguments(node.typeArguments);
+ return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
}
- Statement visitGetLazyStatic(cps_ir.GetLazyStatic node) {
- // In the tree IR, GetStatic handles lazy fields because tree
- // expressions are allowed to have side effects.
- GetStatic value = new GetStatic(node.element, node.sourceInformation);
- return continueWithExpression(node.continuation, value);
+ Expression visitGetStatic(cps_ir.GetStatic node) {
+ return new GetStatic(node.element, node.sourceInformation);
}
Expression visitSetStatic(cps_ir.SetStatic node) {
@@ -600,26 +638,6 @@
translateArguments(node.arguments));
}
- Statement visitForeignCode(cps_ir.ForeignCode node) {
- if (node.codeTemplate.isExpression) {
- Expression foreignCode = new ForeignExpression(
- node.codeTemplate,
- node.type,
- node.arguments.map(getVariableUse).toList(growable: false),
- node.nativeBehavior,
- node.dependency);
- return continueWithExpression(node.continuation, foreignCode);
- } else {
- assert(node.continuation.definition.body is cps_ir.Unreachable);
- return new ForeignStatement(
- node.codeTemplate,
- node.type,
- node.arguments.map(getVariableUse).toList(growable: false),
- node.nativeBehavior,
- node.dependency);
- }
- }
-
Expression visitGetLength(cps_ir.GetLength node) {
return new GetLength(getVariableUse(node.object));
}
@@ -634,5 +652,19 @@
getVariableUse(node.index),
getVariableUse(node.value));
}
+
+ /********** UNUSED VISIT METHODS *************/
+
+ unexpectedNode(cps_ir.Node node) {
+ internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
+ }
+
+ visitFunctionDefinition(cps_ir.FunctionDefinition node) {
+ unexpectedNode(node);
+ }
+ visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
+ visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
+ visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
+ visitIsTrue(cps_ir.IsTrue node) => unexpectedNode(node);
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 07a5168..c23efd5 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -4,7 +4,6 @@
library tree_ir_nodes;
-import '../constants/expressions.dart';
import '../constants/values.dart' as values;
import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
import '../elements/elements.dart';
@@ -816,8 +815,9 @@
class Interceptor extends Expression {
Expression input;
Set<ClassElement> interceptedClasses;
+ final SourceInformation sourceInformation;
- Interceptor(this.input, this.interceptedClasses);
+ Interceptor(this.input, this.interceptedClasses, this.sourceInformation);
accept(ExpressionVisitor visitor) {
return visitor.visitInterceptor(this);
@@ -1108,9 +1108,15 @@
visitStatement(node.next);
}
- visitExpressionStatement(ExpressionStatement node) {
- visitExpression(node.expression);
- visitStatement(node.next);
+ visitExpressionStatement(ExpressionStatement inputNode) {
+ // Iterate over chains of expression statements to avoid deep recursion.
+ Statement node = inputNode;
+ while (node is ExpressionStatement) {
+ ExpressionStatement stmt = node;
+ visitExpression(stmt.expression);
+ node = stmt.next;
+ }
+ visitStatement(node);
}
visitTry(Try node) {
@@ -1326,9 +1332,18 @@
}
visitExpressionStatement(ExpressionStatement node) {
- node.expression = visitExpression(node.expression);
+ // Iterate over chains of expression statements to avoid deep recursion.
+ Statement first = node;
+ while (true) {
+ node.expression = visitExpression(node.expression);
+ if (node.next is ExpressionStatement) {
+ node = node.next;
+ } else {
+ break;
+ }
+ }
node.next = visitStatement(node.next);
- return node;
+ return first;
}
visitTry(Try node) {
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 63d1a05..f07a030 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -92,7 +92,9 @@
visitBreak(Break node) {
_addStatement(node);
- blocks.last.addEdgeTo(breakTargets[node.target]);
+ if (breakTargets.containsKey(node.target)) {
+ blocks.last.addEdgeTo(breakTargets[node.target]);
+ }
}
visitContinue(Continue node) {
@@ -274,7 +276,9 @@
}
visitBreak(Break node) {
- printStatement(null, "break ${collector.breakTargets[node.target].name}");
+ Block block = collector.breakTargets[node.target];
+ String name = block != null ? block.name : '<missing label>';
+ printStatement(null, "break $name");
}
visitContinue(Continue node) {
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
new file mode 100644
index 0000000..11d9e09
--- /dev/null
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -0,0 +1,165 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.world.class_set;
+
+import 'dart:collection' show IterableBase;
+import '../elements/elements.dart' show ClassElement;
+import '../util/util.dart' show Link;
+
+/// Node for [cls] in a tree forming the subclass relation of [ClassElement]s.
+///
+/// This is used by the [ClassWorld] to perform queries on subclass and subtype
+/// relations.
+// TODO(johnniwinther): Use this for `ClassWorld.subtypesOf`.
+class ClassHierarchyNode {
+ final ClassElement cls;
+
+ /// `true` if [cls] has been directly instantiated.
+ ///
+ /// For instance `C` but _not_ `B` in:
+ /// class B {}
+ /// class C extends B {}
+ /// main() => new C();
+ ///
+ bool isDirectlyInstantiated = false;
+
+ /// `true` if [cls] has been instantiated through subclasses.
+ ///
+ /// For instance `A` and `B` but _not_ `C` in:
+ /// class A {}
+ /// class B extends A {}
+ /// class C extends B {}
+ /// main() => [new B(), new C()];
+ ///
+ bool isIndirectlyInstantiated = false;
+
+ /// The nodes for the direct subclasses of [cls].
+ Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>();
+
+ ClassHierarchyNode(this.cls);
+
+ /// Adds [subclass] as a direct subclass of [cls].
+ void addDirectSubclass(ClassHierarchyNode subclass) {
+ assert(subclass.cls.superclass == cls);
+ assert(!_directSubclasses.contains(subclass));
+ _directSubclasses = _directSubclasses.prepend(subclass);
+ }
+
+ /// `true` if [cls] has been directly or indirectly instantiated.
+ bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated;
+
+ /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
+ /// If [directlyInstantiated] is `true`, the iterable only returns the
+ /// directly instantiated subclasses of [cls].
+ Iterable<ClassElement> subclasses({bool directlyInstantiated: true}) {
+ return new ClassHierarchyNodeIterable(
+ this, directlyInstantiatedOnly: directlyInstantiated);
+ }
+
+ /// Returns an [Iterable] of the strict subclasses of [cls] _not_ including
+ /// [cls] itself. If [directlyInstantiated] is `true`, the iterable only
+ /// returns the directly instantiated subclasses of [cls].
+ Iterable<ClassElement> strictSubclasses(
+ {bool directlyInstantiated: true}) {
+ return new ClassHierarchyNodeIterable(this,
+ includeRoot: false, directlyInstantiatedOnly: directlyInstantiated);
+ }
+
+ String toString() => cls.toString();
+}
+
+/// Iterable for subclasses of a [ClassHierarchyNode].
+class ClassHierarchyNodeIterable extends IterableBase<ClassElement> {
+ final ClassHierarchyNode root;
+ final bool includeRoot;
+ final bool directlyInstantiatedOnly;
+
+ ClassHierarchyNodeIterable(
+ this.root,
+ {this.includeRoot: true,
+ this.directlyInstantiatedOnly: false}) {
+ if (root == null) throw new StateError("No root for iterable.");
+ }
+
+ @override
+ Iterator<ClassElement> get iterator {
+ return new ClassHierarchyNodeIterator(this);
+ }
+}
+
+/// Iterator for subclasses of a [ClassHierarchyNode].
+///
+/// Classes are returned in pre-order DFS fashion.
+class ClassHierarchyNodeIterator implements Iterator<ClassElement> {
+ final ClassHierarchyNodeIterable iterable;
+
+ /// The class node holding the [current] class.
+ ///
+ /// This is `null` before the first call to [moveNext] and at the end of
+ /// iteration, i.e. after [moveNext] has returned `false`.
+ ClassHierarchyNode currentNode;
+
+ /// Stack of pending class nodes.
+ ///
+ /// This is `null` before the first call to [moveNext].
+ Link<ClassHierarchyNode> stack;
+
+ ClassHierarchyNodeIterator(this.iterable);
+
+ ClassHierarchyNode get root => iterable.root;
+
+ bool get includeRoot => iterable.includeRoot;
+
+ bool get directlyInstantiatedOnly => iterable.directlyInstantiatedOnly;
+
+ @override
+ ClassElement get current {
+ return currentNode != null ? currentNode.cls : null;
+ }
+
+ @override
+ bool moveNext() {
+ if (stack == null) {
+ // First call to moveNext
+ stack = const Link<ClassHierarchyNode>().prepend(root);
+ return _findNext();
+ } else {
+ // Initialized state.
+ if (currentNode == null) return false;
+ return _findNext();
+ }
+ }
+
+ /// Find the next class using the [stack].
+ bool _findNext() {
+ while (true) {
+ if (stack.isEmpty) {
+ // No more classes. Set [currentNode] to `null` to signal the end of
+ // iteration.
+ currentNode = null;
+ return false;
+ }
+ currentNode = stack.head;
+ stack = stack.tail;
+ for (Link<ClassHierarchyNode> link = currentNode._directSubclasses;
+ !link.isEmpty;
+ link = link.tail) {
+ stack = stack.prepend(link.head);
+ }
+ if (_isValid(currentNode)) {
+ return true;
+ }
+ }
+ }
+
+ /// Returns `true` if the class of [node] is a valid result for this iterator.
+ bool _isValid(ClassHierarchyNode node) {
+ if (!includeRoot && node == root) return false;
+ if (directlyInstantiatedOnly && !node.isDirectlyInstantiated) return false;
+ return true;
+ }
+}
+
+
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index 28715e6..aa90f73 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -4,6 +4,8 @@
library universe;
+import 'dart:collection';
+
import '../elements/elements.dart';
import '../dart2jslib.dart';
import '../dart_types.dart';
@@ -277,8 +279,21 @@
return masks.add(mask);
}
+ Map<Selector, TypeMaskSet> _asUnmodifiable(Map<Selector, TypeMaskSet> map) {
+ if (map == null) return null;
+ return new UnmodifiableMapView(map);
+ }
+
Map<Selector, TypeMaskSet> invocationsByName(String name) {
- return _invokedNames[name];
+ return _asUnmodifiable(_invokedNames[name]);
+ }
+
+ Map<Selector, TypeMaskSet> getterInvocationsByName(String name) {
+ return _asUnmodifiable(_invokedGetters[name]);
+ }
+
+ Map<Selector, TypeMaskSet> setterInvocationsByName(String name) {
+ return _asUnmodifiable(_invokedSetters[name]);
}
void forEachInvokedName(
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index ffbcb5e..570ccf4 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -260,6 +260,8 @@
source_file_provider.SourceFileProvider sourceFileProvider = null;
sourceFileProvider.getSourceFile(null);
world.hasAnyUserDefinedGetter(null, null);
+ world.subclassesOf(null);
+ world.classHierarchyNode(null);
typeGraphInferrer.getCallersOf(null);
dart_types.Types.sorted(null);
new dart_types.Types(compiler).copy(compiler);
@@ -284,8 +286,7 @@
useIr(ir_builder.IrBuilder builder) {
builder
- ..buildStringConstant(null)
- ..buildDynamicGet(null, null, null);
+ ..buildStringConstant(null);
}
useCompiler(dart2jslib.Compiler compiler) {
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index e2f2fb3..5e5d603 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -2,9 +2,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.
-part of dart2js;
-
-const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
/**
* The messages in this file should meet the following guide lines:
@@ -63,9 +60,388 @@
* 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
* combine the first two in [template] and the last in [howToFix].
*/
+
+library dart2js.messages;
+
+import 'dart2jslib.dart';
+import 'scanner/scannerlib.dart';
+
+const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
+
+/// Keys for the [MessageTemplate]s.
+enum MessageKind {
+ ABSTRACT_CLASS_INSTANTIATION,
+ ABSTRACT_GETTER,
+ ABSTRACT_METHOD,
+ ABSTRACT_SETTER,
+ ACCESSED_IN_CLOSURE,
+ ACCESSED_IN_CLOSURE_HERE,
+ ADDITIONAL_ARGUMENT,
+ ADDITIONAL_TYPE_ARGUMENT,
+ ALREADY_INITIALIZED,
+ AMBIGUOUS_LOCATION,
+ AMBIGUOUS_REEXPORT,
+ ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
+ ASSIGNING_METHOD,
+ ASSIGNING_METHOD_IN_SUPER,
+ ASSIGNING_TYPE,
+ ASYNC_KEYWORD_AS_IDENTIFIER,
+ ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
+ ASYNC_MODIFIER_ON_CONSTRUCTOR,
+ ASYNC_MODIFIER_ON_SETTER,
+ AWAIT_MEMBER_NOT_FOUND,
+ AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE,
+ BAD_INPUT_CHARACTER,
+ BEFORE_TOP_LEVEL,
+ BINARY_OPERATOR_BAD_ARITY,
+ BODY_EXPECTED,
+ CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
+ CANNOT_EXTEND,
+ CANNOT_EXTEND_ENUM,
+ CANNOT_EXTEND_MALFORMED,
+ CANNOT_FIND_CONSTRUCTOR,
+ CANNOT_IMPLEMENT,
+ CANNOT_IMPLEMENT_ENUM,
+ CANNOT_IMPLEMENT_MALFORMED,
+ CANNOT_INSTANTIATE_ENUM,
+ CANNOT_INSTANTIATE_TYPE_VARIABLE,
+ CANNOT_INSTANTIATE_TYPEDEF,
+ CANNOT_MIXIN,
+ CANNOT_MIXIN_ENUM,
+ CANNOT_MIXIN_MALFORMED,
+ CANNOT_OVERRIDE_FIELD_WITH_METHOD,
+ CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT,
+ CANNOT_OVERRIDE_GETTER_WITH_METHOD,
+ CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT,
+ CANNOT_OVERRIDE_METHOD_WITH_FIELD,
+ CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT,
+ CANNOT_OVERRIDE_METHOD_WITH_GETTER,
+ CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT,
+ CANNOT_RESOLVE,
+ CANNOT_RESOLVE_AWAIT,
+ CANNOT_RESOLVE_AWAIT_IN_CLOSURE,
+ CANNOT_RESOLVE_CONSTRUCTOR,
+ CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT,
+ CANNOT_RESOLVE_GETTER,
+ CANNOT_RESOLVE_IN_INITIALIZER,
+ CANNOT_RESOLVE_SETTER,
+ CANNOT_RESOLVE_TYPE,
+ CANNOT_RETURN_FROM_CONSTRUCTOR,
+ CLASS_NAME_EXPECTED,
+ COMPILER_CRASHED,
+ COMPLEX_RETURNING_NSM,
+ COMPLEX_THROWING_NSM,
+ CONSIDER_ANALYZE_ALL,
+ CONST_CALLS_NON_CONST,
+ CONST_CALLS_NON_CONST_FOR_IMPLICIT,
+ CONST_CONSTRUCTOR_HAS_BODY,
+ CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
+ CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR,
+ CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD,
+ CONST_MAP_KEY_OVERRIDES_EQUALS,
+ CONST_WITHOUT_INITIALIZER,
+ CONSTRUCTOR_CALL_EXPECTED,
+ CONSTRUCTOR_IS_NOT_CONST,
+ CONSTRUCTOR_WITH_RETURN_TYPE,
+ CYCLIC_CLASS_HIERARCHY,
+ CYCLIC_COMPILE_TIME_CONSTANTS,
+ CYCLIC_REDIRECTING_FACTORY,
+ CYCLIC_TYPE_VARIABLE,
+ CYCLIC_TYPEDEF,
+ CYCLIC_TYPEDEF_ONE,
+ DART_EXT_NOT_SUPPORTED,
+ DEFERRED_COMPILE_TIME_CONSTANT,
+ DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION,
+ DEFERRED_LIBRARY_DART_2_DART,
+ DEFERRED_LIBRARY_DUPLICATE_PREFIX,
+ DEFERRED_LIBRARY_WITHOUT_PREFIX,
+ DEFERRED_OLD_SYNTAX,
+ DEFERRED_TYPE_ANNOTATION,
+ DEPRECATED_TYPEDEF_MIXIN_SYNTAX,
+ DIRECTLY_THROWING_NSM,
+ DUPLICATE_DEFINITION,
+ DUPLICATE_EXPORT,
+ DUPLICATE_EXPORT_CONT,
+ DUPLICATE_EXPORT_DECL,
+ DUPLICATE_EXTENDS_IMPLEMENTS,
+ DUPLICATE_IMPLEMENTS,
+ DUPLICATE_IMPORT,
+ DUPLICATE_INITIALIZER,
+ DUPLICATE_LABEL,
+ DUPLICATE_SUPER_INITIALIZER,
+ DUPLICATE_TYPE_VARIABLE_NAME,
+ DUPLICATED_LIBRARY_NAME,
+ DUPLICATED_LIBRARY_RESOURCE,
+ DUPLICATED_PART_OF,
+ DUPLICATED_RESOURCE,
+ EMPTY_CATCH_DECLARATION,
+ EMPTY_ENUM_DECLARATION,
+ EQUAL_MAP_ENTRY_KEY,
+ EXISTING_DEFINITION,
+ EXISTING_LABEL,
+ EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+ EXPONENT_MISSING,
+ EXPORT_BEFORE_PARTS,
+ EXTERNAL_WITH_BODY,
+ EXTRA_CATCH_DECLARATION,
+ EXTRA_FORMALS,
+ EXTRANEOUS_MODIFIER,
+ EXTRANEOUS_MODIFIER_REPLACE,
+ FACTORY_REDIRECTION_IN_NON_FACTORY,
+ FINAL_FUNCTION_TYPE_PARAMETER,
+ FINAL_WITHOUT_INITIALIZER,
+ FORMAL_DECLARED_CONST,
+ FORMAL_DECLARED_STATIC,
+ FUNCTION_TYPE_FORMAL_WITH_DEFAULT,
+ FUNCTION_WITH_INITIALIZER,
+ GENERIC,
+ GETTER_MISMATCH,
+ GETTER_NOT_FOUND,
+ HEX_DIGIT_EXPECTED,
+ HIDDEN_HINTS,
+ HIDDEN_IMPLICIT_IMPORT,
+ HIDDEN_IMPORT,
+ HIDDEN_WARNINGS,
+ HIDDEN_WARNINGS_HINTS,
+ IF_NULL_ASSIGNING_TYPE,
+ ILLEGAL_CONST_FIELD_MODIFIER,
+ ILLEGAL_CONSTRUCTOR_MODIFIERS,
+ ILLEGAL_FINAL_METHOD_MODIFIER,
+ ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
+ ILLEGAL_MIXIN_CONSTRUCTOR,
+ ILLEGAL_MIXIN_CYCLE,
+ ILLEGAL_MIXIN_OBJECT,
+ ILLEGAL_MIXIN_SUPER_USE,
+ ILLEGAL_MIXIN_SUPERCLASS,
+ ILLEGAL_MIXIN_WITH_SUPER,
+ ILLEGAL_SETTER_FORMALS,
+ ILLEGAL_STATIC,
+ ILLEGAL_SUPER_SEND,
+ IMPORT_BEFORE_PARTS,
+ IMPORT_EXPERIMENTAL_MIRRORS,
+ IMPORT_PART_OF,
+ IMPORTED_HERE,
+ INHERIT_GETTER_AND_METHOD,
+ INHERITED_EXPLICIT_GETTER,
+ INHERITED_IMPLICIT_GETTER,
+ INHERITED_METHOD,
+ INIT_STATIC_FIELD,
+ INITIALIZING_FORMAL_NOT_ALLOWED,
+ INSTANCE_STATIC_SAME_NAME,
+ INSTANCE_STATIC_SAME_NAME_CONT,
+ INTERNAL_LIBRARY,
+ INTERNAL_LIBRARY_FROM,
+ INVALID_ARGUMENT_AFTER_NAMED,
+ INVALID_AWAIT_FOR,
+ INVALID_BREAK,
+ INVALID_CASE_DEFAULT,
+ INVALID_CONSTRUCTOR_ARGUMENTS,
+ INVALID_CONSTRUCTOR_NAME,
+ INVALID_CONTINUE,
+ INVALID_FOR_IN,
+ INVALID_INITIALIZER,
+ INVALID_OVERRIDDEN_FIELD,
+ INVALID_OVERRIDDEN_GETTER,
+ INVALID_OVERRIDDEN_METHOD,
+ INVALID_OVERRIDDEN_SETTER,
+ INVALID_OVERRIDE_FIELD,
+ INVALID_OVERRIDE_FIELD_WITH_GETTER,
+ INVALID_OVERRIDE_FIELD_WITH_SETTER,
+ INVALID_OVERRIDE_GETTER,
+ INVALID_OVERRIDE_GETTER_WITH_FIELD,
+ INVALID_OVERRIDE_METHOD,
+ INVALID_OVERRIDE_SETTER,
+ INVALID_OVERRIDE_SETTER_WITH_FIELD,
+ INVALID_PACKAGE_URI,
+ INVALID_PARAMETER,
+ INVALID_RECEIVER_IN_INITIALIZER,
+ INVALID_SOURCE_FILE_LOCATION,
+ INVALID_SYMBOL,
+ INVALID_SYNC_MODIFIER,
+ INVALID_TYPE_VARIABLE_BOUND,
+ INVALID_UNNAMED_CONSTRUCTOR_NAME,
+ INVALID_URI,
+ INVALID_USE_OF_SUPER,
+ LIBRARY_NAME_MISMATCH,
+ LIBRARY_NOT_FOUND,
+ LIBRARY_TAG_MUST_BE_FIRST,
+ MAIN_NOT_A_FUNCTION,
+ MAIN_WITH_EXTRA_PARAMETER,
+ MALFORMED_STRING_LITERAL,
+ MEMBER_NOT_FOUND,
+ MEMBER_NOT_STATIC,
+ MEMBER_USES_CLASS_NAME,
+ METHOD_NOT_FOUND,
+ MINUS_OPERATOR_BAD_ARITY,
+ MIRROR_BLOAT,
+ MIRROR_IMPORT,
+ MIRROR_IMPORT_NO_USAGE,
+ MIRRORS_CANNOT_FIND_IN_ELEMENT,
+ MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
+ MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
+ MIRRORS_EXPECTED_STRING,
+ MIRRORS_EXPECTED_STRING_OR_LIST,
+ MIRRORS_EXPECTED_STRING_OR_TYPE,
+ MIRRORS_EXPECTED_STRING_TYPE_OR_LIST,
+ MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+ MISSING_ARGUMENT,
+ MISSING_ENUM_CASES,
+ MISSING_FACTORY_KEYWORD,
+ MISSING_FORMALS,
+ MISSING_LIBRARY_NAME,
+ MISSING_MAIN,
+ MISSING_PART_OF_TAG,
+ MISSING_TOKEN_AFTER_THIS,
+ MISSING_TOKEN_BEFORE_THIS,
+ MISSING_TYPE_ARGUMENT,
+ MULTI_INHERITANCE,
+ NAMED_ARGUMENT_NOT_FOUND,
+ NAMED_FUNCTION_EXPRESSION,
+ NAMED_PARAMETER_WITH_EQUALS,
+ NATIVE_NOT_SUPPORTED,
+ NO_BREAK_TARGET,
+ NO_CATCH_NOR_FINALLY,
+ NO_CONTINUE_TARGET,
+ NO_INSTANCE_AVAILABLE,
+ NO_MATCHING_CONSTRUCTOR,
+ NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT,
+ NO_STATIC_OVERRIDE,
+ NO_STATIC_OVERRIDE_CONT,
+ NO_SUCH_LIBRARY_MEMBER,
+ NO_SUCH_METHOD_IN_NATIVE,
+ NO_SUCH_SUPER_MEMBER,
+ NO_SUPER_IN_STATIC,
+ NO_THIS_AVAILABLE,
+ NON_CONST_BLOAT,
+ NOT_A_COMPILE_TIME_CONSTANT,
+ NOT_A_FIELD,
+ NOT_A_PREFIX,
+ NOT_A_TYPE,
+ NOT_ASSIGNABLE,
+ NOT_CALLABLE,
+ NOT_INSTANCE_FIELD,
+ NOT_MORE_SPECIFIC,
+ NOT_MORE_SPECIFIC_SUBTYPE,
+ NOT_MORE_SPECIFIC_SUGGESTION,
+ NULL_NOT_ALLOWED,
+ ONLY_ONE_LIBRARY_TAG,
+ OPERATOR_NAMED_PARAMETERS,
+ OPERATOR_NOT_FOUND,
+ OPERATOR_OPTIONAL_PARAMETERS,
+ OPTIONAL_PARAMETER_IN_CATCH,
+ OVERRIDE_EQUALS_NOT_HASH_CODE,
+ PARAMETER_NAME_EXPECTED,
+ PARAMETER_WITH_MODIFIER_IN_CATCH,
+ PARAMETER_WITH_TYPE_IN_CATCH,
+ PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION,
+ PATCH_NO_GETTER,
+ PATCH_NO_SETTER,
+ PATCH_NON_CLASS,
+ PATCH_NON_CONSTRUCTOR,
+ PATCH_NON_EXISTING,
+ PATCH_NON_EXTERNAL,
+ PATCH_NON_FUNCTION,
+ PATCH_NON_GETTER,
+ PATCH_NON_SETTER,
+ PATCH_NONPATCHABLE,
+ PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
+ PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
+ PATCH_PARAMETER_MISMATCH,
+ PATCH_PARAMETER_TYPE_MISMATCH,
+ PATCH_POINT_TO_CLASS,
+ PATCH_POINT_TO_CONSTRUCTOR,
+ PATCH_POINT_TO_FUNCTION,
+ PATCH_POINT_TO_GETTER,
+ PATCH_POINT_TO_PARAMETER,
+ PATCH_POINT_TO_SETTER,
+ PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
+ PATCH_RETURN_TYPE_MISMATCH,
+ PLEASE_REPORT_THE_CRASH,
+ POSITIONAL_PARAMETER_WITH_EQUALS,
+ POTENTIAL_MUTATION,
+ POTENTIAL_MUTATION_HERE,
+ POTENTIAL_MUTATION_IN_CLOSURE,
+ POTENTIAL_MUTATION_IN_CLOSURE_HERE,
+ PREAMBLE,
+ PREFIX_AS_EXPRESSION,
+ PRIVATE_ACCESS,
+ PRIVATE_IDENTIFIER,
+ PRIVATE_NAMED_PARAMETER,
+ READ_SCRIPT_ERROR,
+ READ_SELF_ERROR,
+ REDIRECTING_CONSTRUCTOR_CYCLE,
+ REDIRECTING_CONSTRUCTOR_HAS_BODY,
+ REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER,
+ REDIRECTING_FACTORY_WITH_DEFAULT,
+ REFERENCE_IN_INITIALIZATION,
+ REQUIRED_PARAMETER_WITH_DEFAULT,
+ RETURN_IN_GENERATOR,
+ RETURN_NOTHING,
+ RETURN_VALUE_IN_VOID,
+ SETTER_MISMATCH,
+ SETTER_NOT_FOUND,
+ SETTER_NOT_FOUND_IN_SUPER,
+ STATIC_FUNCTION_BLOAT,
+ STRING_EXPECTED,
+ SUPER_INITIALIZER_IN_OBJECT,
+ SWITCH_CASE_FORBIDDEN,
+ SWITCH_CASE_TYPES_NOT_EQUAL,
+ SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
+ SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
+ TERNARY_OPERATOR_BAD_ARITY,
+ THIS_IS_THE_DECLARATION,
+ THIS_IS_THE_METHOD,
+ THIS_IS_THE_PART_OF_TAG,
+ THIS_PROPERTY,
+ THROW_WITHOUT_EXPRESSION,
+ TOP_LEVEL_VARIABLE_DECLARED_STATIC,
+ TYPE_ARGUMENT_COUNT_MISMATCH,
+ TYPE_VARIABLE_IN_CONSTANT,
+ TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
+ TYPEDEF_FORMAL_WITH_DEFAULT,
+ UNARY_OPERATOR_BAD_ARITY,
+ UNBOUND_LABEL,
+ UNIMPLEMENTED_EXPLICIT_GETTER,
+ UNIMPLEMENTED_EXPLICIT_SETTER,
+ UNIMPLEMENTED_GETTER,
+ UNIMPLEMENTED_GETTER_ONE,
+ UNIMPLEMENTED_IMPLICIT_GETTER,
+ UNIMPLEMENTED_IMPLICIT_SETTER,
+ UNIMPLEMENTED_METHOD,
+ UNIMPLEMENTED_METHOD_CONT,
+ UNIMPLEMENTED_METHOD_ONE,
+ UNIMPLEMENTED_SETTER,
+ UNIMPLEMENTED_SETTER_ONE,
+ UNMATCHED_TOKEN,
+ UNSUPPORTED_BANG_EQ_EQ,
+ UNSUPPORTED_EQ_EQ_EQ,
+ UNSUPPORTED_LITERAL_SYMBOL,
+ UNSUPPORTED_PREFIX_PLUS,
+ UNSUPPORTED_THROW_WITHOUT_EXP,
+ UNTERMINATED_COMMENT,
+ UNTERMINATED_STRING,
+ UNTERMINATED_TOKEN,
+ UNUSED_CLASS,
+ UNUSED_LABEL,
+ UNUSED_METHOD,
+ UNUSED_TYPEDEF,
+ VAR_FUNCTION_TYPE_PARAMETER,
+ VOID_EXPRESSION,
+ VOID_NOT_ALLOWED,
+ VOID_VARIABLE,
+ WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT,
+ WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
+ YIELDING_MODIFIER_ON_ARROW_BODY,
+}
+
+/// A message template for an error, warning, hint or info message generated
+/// by the compiler. Each template is associated with a [MessageKind] that
+/// uniquely identifies the message template.
// TODO(johnnniwinther): For Infos, consider adding a reference to the
// error/warning/hint that they belong to.
-class MessageKind {
+class MessageTemplate {
+ final MessageKind kind;
+
/// Should describe what is wrong and why.
final String template;
@@ -85,141 +461,180 @@
/// Additional options needed for the examples to work.
final List<String> options;
- const MessageKind(this.template,
- {this.howToFix,
- this.examples,
- this.options: const <String>[]});
+ const MessageTemplate(
+ this.kind,
+ this.template,
+ {this.howToFix,
+ this.examples,
+ this.options: const <String>[]});
- /// Do not use this. It is here for legacy and debugging. It violates item 4
- /// above.
- static const MessageKind GENERIC = const MessageKind('#{text}');
+ /// All templates used by the compiler.
+ ///
+ /// The map is complete mapping from [MessageKind] to their corresponding
+ /// [MessageTemplate].
+ static const Map<MessageKind, MessageTemplate> TEMPLATES =
+ const <MessageKind, MessageTemplate>{
+ /// Do not use this. It is here for legacy and debugging. It violates item
+ /// 4 of the guide lines for error messages in the beginning of the file.
+ MessageKind.GENERIC:
+ const MessageTemplate(MessageKind.GENERIC, '#{text}'),
- static const MessageKind NOT_ASSIGNABLE = const MessageKind(
- "'#{fromType}' is not assignable to '#{toType}'.");
+ MessageKind.NOT_ASSIGNABLE:
+ const MessageTemplate(MessageKind.NOT_ASSIGNABLE,
+ "'#{fromType}' is not assignable to '#{toType}'."),
- static const MessageKind VOID_EXPRESSION = const MessageKind(
- "Expression does not yield a value.");
+ MessageKind.VOID_EXPRESSION:
+ const MessageTemplate(MessageKind.VOID_EXPRESSION,
+ "Expression does not yield a value."),
- static const MessageKind VOID_VARIABLE = const MessageKind(
- "Variable cannot be of type void.");
+ MessageKind.VOID_VARIABLE:
+ const MessageTemplate(MessageKind.VOID_VARIABLE,
+ "Variable cannot be of type void."),
- static const MessageKind RETURN_VALUE_IN_VOID = const MessageKind(
- "Cannot return value from void function.");
+ MessageKind.RETURN_VALUE_IN_VOID:
+ const MessageTemplate(MessageKind.RETURN_VALUE_IN_VOID,
+ "Cannot return value from void function."),
- static const MessageKind RETURN_NOTHING = const MessageKind(
- "Value of type '#{returnType}' expected.");
+ MessageKind.RETURN_NOTHING:
+ const MessageTemplate(MessageKind.RETURN_NOTHING,
+ "Value of type '#{returnType}' expected."),
- static const MessageKind MISSING_ARGUMENT = const MessageKind(
- "Missing argument of type '#{argumentType}'.");
+ MessageKind.MISSING_ARGUMENT:
+ const MessageTemplate(MessageKind.MISSING_ARGUMENT,
+ "Missing argument of type '#{argumentType}'."),
- static const MessageKind ADDITIONAL_ARGUMENT = const MessageKind(
- "Additional argument.");
+ MessageKind.ADDITIONAL_ARGUMENT:
+ const MessageTemplate(MessageKind.ADDITIONAL_ARGUMENT,
+ "Additional argument."),
- static const MessageKind NAMED_ARGUMENT_NOT_FOUND = const MessageKind(
- "No named argument '#{argumentName}' found on method.");
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND:
+ const MessageTemplate(MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ "No named argument '#{argumentName}' found on method."),
- static const MessageKind MEMBER_NOT_FOUND = const MessageKind(
- "No member named '#{memberName}' in class '#{className}'.");
+ MessageKind.MEMBER_NOT_FOUND:
+ const MessageTemplate(MessageKind.MEMBER_NOT_FOUND,
+ "No member named '#{memberName}' in class '#{className}'."),
- static const MessageKind AWAIT_MEMBER_NOT_FOUND = const MessageKind(
- "No member named 'await' in class '#{className}'.",
- howToFix: "Did you mean to add the 'async' marker "
- "to '#{functionName}'?",
- examples: const ["""
+ MessageKind.AWAIT_MEMBER_NOT_FOUND:
+ const MessageTemplate(MessageKind.AWAIT_MEMBER_NOT_FOUND,
+ "No member named 'await' in class '#{className}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to '#{functionName}'?",
+ examples: const ["""
class A {
m() => await -3;
}
main() => new A().m();
-"""]);
+"""]),
- static const MessageKind AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE =
- const MessageKind("No member named 'await' in class '#{className}'.",
- howToFix: "Did you mean to add the 'async' marker "
- "to the enclosing function?",
- examples: const ["""
+ MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE:
+ const MessageTemplate(MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE,
+ "No member named 'await' in class '#{className}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to the enclosing function?",
+ examples: const ["""
class A {
m() => () => await -3;
}
main() => new A().m();
-"""]);
+"""]),
- static const MessageKind METHOD_NOT_FOUND = const MessageKind(
- "No method named '#{memberName}' in class '#{className}'.");
+ MessageKind.METHOD_NOT_FOUND:
+ const MessageTemplate(MessageKind.METHOD_NOT_FOUND,
+ "No method named '#{memberName}' in class '#{className}'."),
- static const MessageKind OPERATOR_NOT_FOUND = const MessageKind(
- "No operator '#{memberName}' in class '#{className}'.");
+ MessageKind.OPERATOR_NOT_FOUND:
+ const MessageTemplate(MessageKind.OPERATOR_NOT_FOUND,
+ "No operator '#{memberName}' in class '#{className}'."),
- static const MessageKind SETTER_NOT_FOUND = const MessageKind(
- "No setter named '#{memberName}' in class '#{className}'.");
+ MessageKind.SETTER_NOT_FOUND:
+ const MessageTemplate(MessageKind.SETTER_NOT_FOUND,
+ "No setter named '#{memberName}' in class '#{className}'."),
- static const MessageKind SETTER_NOT_FOUND_IN_SUPER = const MessageKind(
- "No setter named '#{name}' in superclass of '#{className}'.");
+ MessageKind.SETTER_NOT_FOUND_IN_SUPER:
+ const MessageTemplate(MessageKind.SETTER_NOT_FOUND_IN_SUPER,
+ "No setter named '#{name}' in superclass of '#{className}'."),
- static const MessageKind GETTER_NOT_FOUND = const MessageKind(
- "No getter named '#{memberName}' in class '#{className}'.");
+ MessageKind.GETTER_NOT_FOUND:
+ const MessageTemplate(MessageKind.GETTER_NOT_FOUND,
+ "No getter named '#{memberName}' in class '#{className}'."),
- static const MessageKind NOT_CALLABLE = const MessageKind(
- "'#{elementName}' is not callable.");
+ MessageKind.NOT_CALLABLE:
+ const MessageTemplate(MessageKind.NOT_CALLABLE,
+ "'#{elementName}' is not callable."),
- static const MessageKind MEMBER_NOT_STATIC = const MessageKind(
- "'#{className}.#{memberName}' is not static.");
+ MessageKind.MEMBER_NOT_STATIC:
+ const MessageTemplate(MessageKind.MEMBER_NOT_STATIC,
+ "'#{className}.#{memberName}' is not static."),
- static const MessageKind NO_INSTANCE_AVAILABLE = const MessageKind(
- "'#{name}' is only available in instance methods.");
+ MessageKind.NO_INSTANCE_AVAILABLE:
+ const MessageTemplate(MessageKind.NO_INSTANCE_AVAILABLE,
+ "'#{name}' is only available in instance methods."),
- static const MessageKind NO_THIS_AVAILABLE = const MessageKind(
- "'this' is only available in instance methods.");
+ MessageKind.NO_THIS_AVAILABLE:
+ const MessageTemplate(MessageKind.NO_THIS_AVAILABLE,
+ "'this' is only available in instance methods."),
- static const MessageKind PRIVATE_ACCESS = const MessageKind(
- "'#{name}' is declared private within library "
- "'#{libraryName}'.");
+ MessageKind.PRIVATE_ACCESS:
+ const MessageTemplate(MessageKind.PRIVATE_ACCESS,
+ "'#{name}' is declared private within library "
+ "'#{libraryName}'."),
- static const MessageKind THIS_IS_THE_DECLARATION = const MessageKind(
- "This is the declaration of '#{name}'.");
+ MessageKind.THIS_IS_THE_DECLARATION:
+ const MessageTemplate(MessageKind.THIS_IS_THE_DECLARATION,
+ "This is the declaration of '#{name}'."),
- static const MessageKind THIS_IS_THE_METHOD = const MessageKind(
- "This is the method declaration.");
+ MessageKind.THIS_IS_THE_METHOD:
+ const MessageTemplate(MessageKind.THIS_IS_THE_METHOD,
+ "This is the method declaration."),
- static const MessageKind CANNOT_RESOLVE = const MessageKind(
- "Cannot resolve '#{name}'.");
+ MessageKind.CANNOT_RESOLVE:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE,
+ "Cannot resolve '#{name}'."),
- static const MessageKind CANNOT_RESOLVE_AWAIT = const MessageKind(
- "Cannot resolve '#{name}'.",
- howToFix: "Did you mean to add the 'async' marker "
- "to '#{functionName}'?",
- examples: const [
- "main() => await -3;",
- "foo() => await -3; main() => foo();"
- ]);
+ MessageKind.CANNOT_RESOLVE_AWAIT:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_AWAIT,
+ "Cannot resolve '#{name}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to '#{functionName}'?",
+ examples: const [
+ "main() => await -3;",
+ "foo() => await -3; main() => foo();"
+ ]),
- static const MessageKind CANNOT_RESOLVE_AWAIT_IN_CLOSURE = const MessageKind(
- "Cannot resolve '#{name}'.",
- howToFix: "Did you mean to add the 'async' marker "
- "to the enclosing function?",
- examples: const [
- "main() { (() => await -3)(); }",
- ]);
+ MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE,
+ "Cannot resolve '#{name}'.",
+ howToFix: "Did you mean to add the 'async' marker "
+ "to the enclosing function?",
+ examples: const [
+ "main() { (() => await -3)(); }",
+ ]),
- static const MessageKind CANNOT_RESOLVE_IN_INITIALIZER = const MessageKind(
- "Cannot resolve '#{name}'. It would be implicitly looked up on this "
- "instance, but instances are not available in initializers.",
- howToFix: "Try correcting the unresolved reference or move the "
- "initialization to a constructor body.",
- examples: const ["""
+ MessageKind.CANNOT_RESOLVE_IN_INITIALIZER:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_IN_INITIALIZER,
+ "Cannot resolve '#{name}'. It would be implicitly looked up on this "
+ "instance, but instances are not available in initializers.",
+ howToFix: "Try correcting the unresolved reference or move the "
+ "initialization to a constructor body.",
+ examples: const ["""
class A {
var test = unresolvedName;
}
main() => new A();
-"""]);
+"""]),
- static const MessageKind CANNOT_RESOLVE_CONSTRUCTOR = const MessageKind(
- "Cannot resolve constructor '#{constructorName}'.");
+ MessageKind.CANNOT_RESOLVE_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_CONSTRUCTOR,
+ "Cannot resolve constructor '#{constructorName}'."),
- static const MessageKind CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT =
- const MessageKind("cannot resolve constructor '#{constructorName}'"
- " for implicit super call.",
- howToFix: "Try explicitly invoking a constructor of the super class",
- examples: const ["""
+ MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT:
+ const MessageTemplate(
+ MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT,
+ "cannot resolve constructor '#{constructorName}' "
+ "for implicit super call.",
+ howToFix: "Try explicitly invoking a constructor of the super class",
+ examples: const ["""
class A {
A.foo() {}
}
@@ -227,21 +642,25 @@
B();
}
main() => new B();
-"""]);
+"""]),
- static const MessageKind INVALID_UNNAMED_CONSTRUCTOR_NAME = const MessageKind(
- "Unnamed constructor name must be '#{name}'.");
+ MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME:
+ const MessageTemplate(MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
+ "Unnamed constructor name must be '#{name}'."),
- static const MessageKind INVALID_CONSTRUCTOR_NAME = const MessageKind(
- "Constructor name must start with '#{name}'.");
+ MessageKind.INVALID_CONSTRUCTOR_NAME:
+ const MessageTemplate(MessageKind.INVALID_CONSTRUCTOR_NAME,
+ "Constructor name must start with '#{name}'."),
- static const MessageKind CANNOT_RESOLVE_TYPE = const MessageKind(
- "Cannot resolve type '#{typeName}'.");
+ MessageKind.CANNOT_RESOLVE_TYPE:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_TYPE,
+ "Cannot resolve type '#{typeName}'."),
- static const MessageKind DUPLICATE_DEFINITION = const MessageKind(
- "Duplicate definition of '#{name}'.",
- howToFix: "Try to rename or remove this definition.",
- examples: const ["""
+ MessageKind.DUPLICATE_DEFINITION:
+ const MessageTemplate(MessageKind.DUPLICATE_DEFINITION,
+ "Duplicate definition of '#{name}'.",
+ howToFix: "Try to rename or remove this definition.",
+ examples: const ["""
class C {
void f() {}
int get f => 1;
@@ -251,20 +670,24 @@
new C();
}
-"""]);
+"""]),
- static const MessageKind EXISTING_DEFINITION = const MessageKind(
- "Existing definition of '#{name}'.");
+ MessageKind.EXISTING_DEFINITION:
+ const MessageTemplate(MessageKind.EXISTING_DEFINITION,
+ "Existing definition of '#{name}'."),
- static const MessageKind DUPLICATE_IMPORT = const MessageKind(
- "Duplicate import of '#{name}'.");
+ MessageKind.DUPLICATE_IMPORT:
+ const MessageTemplate(MessageKind.DUPLICATE_IMPORT,
+ "Duplicate import of '#{name}'."),
- static const MessageKind HIDDEN_IMPORT = const MessageKind(
- "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
- "from library '#{hidingUri}'.",
- howToFix: "Try adding 'hide #{name}' to the import of '#{hiddenUri}'.",
- examples: const [
- const {
+ MessageKind.HIDDEN_IMPORT:
+ const MessageTemplate(MessageKind.HIDDEN_IMPORT,
+ "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
+ "from library '#{hidingUri}'.",
+ howToFix:
+ "Try adding 'hide #{name}' to the import of '#{hiddenUri}'.",
+ examples: const [
+ const {
'main.dart':
"""
import 'dart:async'; // This imports a class Future.
@@ -324,16 +747,17 @@
"""
library future;
-class Future {}"""}]);
+class Future {}"""}]),
- static const MessageKind HIDDEN_IMPLICIT_IMPORT = const MessageKind(
- "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
- "from library '#{hidingUri}'.",
- howToFix: "Try adding an explicit "
- "'import \"#{hiddenUri}\" hide #{name}'.",
- examples: const [
- const {
+ MessageKind.HIDDEN_IMPLICIT_IMPORT:
+ const MessageTemplate(MessageKind.HIDDEN_IMPLICIT_IMPORT,
+ "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
+ "from library '#{hidingUri}'.",
+ howToFix: "Try adding an explicit "
+ "'import \"#{hiddenUri}\" hide #{name}'.",
+ examples: const [
+ const {
'main.dart':
"""
// This hides the implicit import of class Type from dart:core.
@@ -375,122 +799,150 @@
main() {
print("Hail Caesar ${Duration.x}");
}
-"""}]);
+"""}]),
- static const MessageKind DUPLICATE_EXPORT = const MessageKind(
- "Duplicate export of '#{name}'.",
- howToFix: "Trying adding 'hide #{name}' to one of the exports.",
- examples: const [const {
+ MessageKind.DUPLICATE_EXPORT:
+ const MessageTemplate(MessageKind.DUPLICATE_EXPORT,
+ "Duplicate export of '#{name}'.",
+ howToFix: "Trying adding 'hide #{name}' to one of the exports.",
+ examples: const [const {
'main.dart': """
export 'decl1.dart';
export 'decl2.dart';
main() {}""",
'decl1.dart': "class Class {}",
-'decl2.dart': "class Class {}"}]);
+'decl2.dart': "class Class {}"}]),
- static const MessageKind DUPLICATE_EXPORT_CONT = const MessageKind(
- "This is another export of '#{name}'.");
+ MessageKind.DUPLICATE_EXPORT_CONT:
+ const MessageTemplate(MessageKind.DUPLICATE_EXPORT_CONT,
+ "This is another export of '#{name}'."),
- static const MessageKind DUPLICATE_EXPORT_DECL = const MessageKind(
- "The exported '#{name}' from export #{uriString} is defined here.");
+ MessageKind.DUPLICATE_EXPORT_DECL:
+ const MessageTemplate(MessageKind.DUPLICATE_EXPORT_DECL,
+ "The exported '#{name}' from export #{uriString} is defined here."),
- static const MessageKind NOT_A_TYPE = const MessageKind(
- "'#{node}' is not a type.");
+ MessageKind.NOT_A_TYPE:
+ const MessageTemplate(MessageKind.NOT_A_TYPE,
+ "'#{node}' is not a type."),
- static const MessageKind NOT_A_PREFIX = const MessageKind(
- "'#{node}' is not a prefix.");
+ MessageKind.NOT_A_PREFIX:
+ const MessageTemplate(MessageKind.NOT_A_PREFIX,
+ "'#{node}' is not a prefix."),
- static const MessageKind PREFIX_AS_EXPRESSION = const MessageKind(
- "Library prefix '#{prefix}' is not a valid expression.");
+ MessageKind.PREFIX_AS_EXPRESSION:
+ const MessageTemplate(MessageKind.PREFIX_AS_EXPRESSION,
+ "Library prefix '#{prefix}' is not a valid expression."),
- static const MessageKind CANNOT_FIND_CONSTRUCTOR = const MessageKind(
- "Cannot find constructor '#{constructorName}'.");
+ MessageKind.CANNOT_FIND_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_FIND_CONSTRUCTOR,
+ "Cannot find constructor '#{constructorName}'."),
- static const MessageKind CYCLIC_CLASS_HIERARCHY = const MessageKind(
- "'#{className}' creates a cycle in the class hierarchy.");
+ MessageKind.CYCLIC_CLASS_HIERARCHY:
+ const MessageTemplate(MessageKind.CYCLIC_CLASS_HIERARCHY,
+ "'#{className}' creates a cycle in the class hierarchy."),
- static const MessageKind CYCLIC_REDIRECTING_FACTORY = const MessageKind(
- 'Redirecting factory leads to a cyclic redirection.');
+ MessageKind.CYCLIC_REDIRECTING_FACTORY:
+ const MessageTemplate(MessageKind.CYCLIC_REDIRECTING_FACTORY,
+ 'Redirecting factory leads to a cyclic redirection.'),
- static const MessageKind INVALID_RECEIVER_IN_INITIALIZER = const MessageKind(
- "Field initializer expected.");
+ MessageKind.INVALID_RECEIVER_IN_INITIALIZER:
+ const MessageTemplate(MessageKind.INVALID_RECEIVER_IN_INITIALIZER,
+ "Field initializer expected."),
- static const MessageKind NO_SUPER_IN_STATIC = const MessageKind(
- "'super' is only available in instance methods.");
+ MessageKind.NO_SUPER_IN_STATIC:
+ const MessageTemplate(MessageKind.NO_SUPER_IN_STATIC,
+ "'super' is only available in instance methods."),
- static const MessageKind DUPLICATE_INITIALIZER = const MessageKind(
- "Field '#{fieldName}' is initialized more than once.");
+ MessageKind.DUPLICATE_INITIALIZER:
+ const MessageTemplate(MessageKind.DUPLICATE_INITIALIZER,
+ "Field '#{fieldName}' is initialized more than once."),
- static const MessageKind ALREADY_INITIALIZED = const MessageKind(
- "'#{fieldName}' was already initialized here.");
+ MessageKind.ALREADY_INITIALIZED:
+ const MessageTemplate(MessageKind.ALREADY_INITIALIZED,
+ "'#{fieldName}' was already initialized here."),
- static const MessageKind INIT_STATIC_FIELD = const MessageKind(
- "Cannot initialize static field '#{fieldName}'.");
+ MessageKind.INIT_STATIC_FIELD:
+ const MessageTemplate(MessageKind.INIT_STATIC_FIELD,
+ "Cannot initialize static field '#{fieldName}'."),
- static const MessageKind NOT_A_FIELD = const MessageKind(
- "'#{fieldName}' is not a field.");
+ MessageKind.NOT_A_FIELD:
+ const MessageTemplate(MessageKind.NOT_A_FIELD,
+ "'#{fieldName}' is not a field."),
- static const MessageKind CONSTRUCTOR_CALL_EXPECTED = const MessageKind(
- "only call to 'this' or 'super' constructor allowed.");
+ MessageKind.CONSTRUCTOR_CALL_EXPECTED:
+ const MessageTemplate(MessageKind.CONSTRUCTOR_CALL_EXPECTED,
+ "only call to 'this' or 'super' constructor allowed."),
- static const MessageKind INVALID_FOR_IN = const MessageKind(
- "Invalid for-in variable declaration.");
+ MessageKind.INVALID_FOR_IN:
+ const MessageTemplate(MessageKind.INVALID_FOR_IN,
+ "Invalid for-in variable declaration."),
- static const MessageKind INVALID_INITIALIZER = const MessageKind(
- "Invalid initializer.");
+ MessageKind.INVALID_INITIALIZER:
+ const MessageTemplate(MessageKind.INVALID_INITIALIZER,
+ "Invalid initializer."),
- static const MessageKind FUNCTION_WITH_INITIALIZER = const MessageKind(
- "Only constructors can have initializers.");
+ MessageKind.FUNCTION_WITH_INITIALIZER:
+ const MessageTemplate(MessageKind.FUNCTION_WITH_INITIALIZER,
+ "Only constructors can have initializers."),
- static const MessageKind REDIRECTING_CONSTRUCTOR_CYCLE = const MessageKind(
- "Cyclic constructor redirection.");
+ MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE:
+ const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE,
+ "Cyclic constructor redirection."),
- static const MessageKind REDIRECTING_CONSTRUCTOR_HAS_BODY = const MessageKind(
- "Redirecting constructor can't have a body.");
+ MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY:
+ const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY,
+ "Redirecting constructor can't have a body."),
- static const MessageKind CONST_CONSTRUCTOR_HAS_BODY = const MessageKind(
- "Const constructor or factory can't have a body.",
- howToFix: "Remove the 'const' keyword or the body",
- examples: const ["""
+ MessageKind.CONST_CONSTRUCTOR_HAS_BODY:
+ const MessageTemplate(MessageKind.CONST_CONSTRUCTOR_HAS_BODY,
+ "Const constructor or factory can't have a body.",
+ howToFix: "Remove the 'const' keyword or the body",
+ examples: const ["""
class C {
const C() {}
}
-main() => new C();"""]);
+main() => new C();"""]),
- static const MessageKind REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER =
- const MessageKind(
- "Redirecting constructor cannot have other initializers.");
+ MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER:
+ const MessageTemplate(
+ MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER,
+ "Redirecting constructor cannot have other initializers."),
- static const MessageKind SUPER_INITIALIZER_IN_OBJECT = const MessageKind(
- "'Object' cannot have a super initializer.");
+ MessageKind.SUPER_INITIALIZER_IN_OBJECT:
+ const MessageTemplate(MessageKind.SUPER_INITIALIZER_IN_OBJECT,
+ "'Object' cannot have a super initializer."),
- static const MessageKind DUPLICATE_SUPER_INITIALIZER = const MessageKind(
- "Cannot have more than one super initializer.");
+ MessageKind.DUPLICATE_SUPER_INITIALIZER:
+ const MessageTemplate(MessageKind.DUPLICATE_SUPER_INITIALIZER,
+ "Cannot have more than one super initializer."),
- static const MessageKind INVALID_CONSTRUCTOR_ARGUMENTS = const MessageKind(
- "Arguments do not match the expected parameters of constructor "
- "'#{constructorName}'.");
+ MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS:
+ const MessageTemplate(MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
+ "Arguments do not match the expected parameters of constructor "
+ "'#{constructorName}'."),
- static const MessageKind NO_MATCHING_CONSTRUCTOR = const MessageKind(
- "'super' call arguments and constructor parameters do not match.");
+ MessageKind.NO_MATCHING_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.NO_MATCHING_CONSTRUCTOR,
+ "'super' call arguments and constructor parameters do not match."),
- static const MessageKind NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT =
- const MessageKind(
- "Implicit 'super' call arguments and constructor parameters "
- "do not match.");
+ MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT:
+ const MessageTemplate(MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT,
+ "Implicit 'super' call arguments and constructor parameters "
+ "do not match."),
- static const MessageKind CONST_CALLS_NON_CONST = const MessageKind(
- "'const' constructor cannot call a non-const constructor.");
+ MessageKind.CONST_CALLS_NON_CONST:
+ const MessageTemplate(MessageKind.CONST_CALLS_NON_CONST,
+ "'const' constructor cannot call a non-const constructor."),
- static const MessageKind CONST_CALLS_NON_CONST_FOR_IMPLICIT =
- const MessageKind(
- "'const' constructor cannot call a non-const constructor. "
- "This constructor has an implicit call to a "
- "super non-const constructor.",
- howToFix: "Try making the super constructor const.",
- examples: const ["""
+ MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT:
+ const MessageTemplate(MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT,
+ "'const' constructor cannot call a non-const constructor. "
+ "This constructor has an implicit call to a "
+ "super non-const constructor.",
+ howToFix: "Try making the super constructor const.",
+ examples: const ["""
class C {
C(); // missing const
}
@@ -498,10 +950,11 @@
final d;
const D(this.d);
}
-main() => new D(0);"""]);
+main() => new D(0);"""]),
- static const MessageKind CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS =
- const MessageKind(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS:
+ const MessageTemplate(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
"Can't declare constructor 'const' on class #{className} "
"because the class contains non-final instance fields.",
howToFix: "Try making all fields final.",
@@ -512,89 +965,113 @@
const C(this.a);
}
-main() => new C(0);"""]);
+main() => new C(0);"""]),
- static const MessageKind CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD =
- const MessageKind("This non-final field prevents using const "
- "constructors.");
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD:
+ const MessageTemplate(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD,
+ "This non-final field prevents using const constructors."),
- static const MessageKind CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR =
- const MessageKind("This const constructor is not allowed due to "
- "non-final fields.");
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR:
+ const MessageTemplate(
+ MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR,
+ "This const constructor is not allowed due to "
+ "non-final fields."),
- static const MessageKind INITIALIZING_FORMAL_NOT_ALLOWED = const MessageKind(
- "Initializing formal parameter only allowed in generative "
- "constructor.");
+ MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED:
+ const MessageTemplate(MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED,
+ "Initializing formal parameter only allowed in generative "
+ "constructor."),
- static const MessageKind INVALID_PARAMETER = const MessageKind(
- "Cannot resolve parameter.");
+ MessageKind.INVALID_PARAMETER:
+ const MessageTemplate(MessageKind.INVALID_PARAMETER,
+ "Cannot resolve parameter."),
- static const MessageKind NOT_INSTANCE_FIELD = const MessageKind(
- "'#{fieldName}' is not an instance field.");
+ MessageKind.NOT_INSTANCE_FIELD:
+ const MessageTemplate(MessageKind.NOT_INSTANCE_FIELD,
+ "'#{fieldName}' is not an instance field."),
- static const MessageKind THIS_PROPERTY = const MessageKind(
- "Expected an identifier.");
+ MessageKind.THIS_PROPERTY:
+ const MessageTemplate(MessageKind.THIS_PROPERTY,
+ "Expected an identifier."),
- static const MessageKind NO_CATCH_NOR_FINALLY = const MessageKind(
- "Expected 'catch' or 'finally'.");
+ MessageKind.NO_CATCH_NOR_FINALLY:
+ const MessageTemplate(MessageKind.NO_CATCH_NOR_FINALLY,
+ "Expected 'catch' or 'finally'."),
- static const MessageKind EMPTY_CATCH_DECLARATION = const MessageKind(
- "Expected an identifier in catch declaration.");
+ MessageKind.EMPTY_CATCH_DECLARATION:
+ const MessageTemplate(MessageKind.EMPTY_CATCH_DECLARATION,
+ "Expected an identifier in catch declaration."),
- static const MessageKind EXTRA_CATCH_DECLARATION = const MessageKind(
- "Extra parameter in catch declaration.");
+ MessageKind.EXTRA_CATCH_DECLARATION:
+ const MessageTemplate(MessageKind.EXTRA_CATCH_DECLARATION,
+ "Extra parameter in catch declaration."),
- static const MessageKind PARAMETER_WITH_TYPE_IN_CATCH = const MessageKind(
- "Cannot use type annotations in catch.");
+ MessageKind.PARAMETER_WITH_TYPE_IN_CATCH:
+ const MessageTemplate(MessageKind.PARAMETER_WITH_TYPE_IN_CATCH,
+ "Cannot use type annotations in catch."),
- static const MessageKind PARAMETER_WITH_MODIFIER_IN_CATCH = const MessageKind(
- "Cannot use modifiers in catch.");
+ MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH:
+ const MessageTemplate(MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH,
+ "Cannot use modifiers in catch."),
- static const MessageKind OPTIONAL_PARAMETER_IN_CATCH = const MessageKind(
- "Cannot use optional parameters in catch.");
+ MessageKind.OPTIONAL_PARAMETER_IN_CATCH:
+ const MessageTemplate(MessageKind.OPTIONAL_PARAMETER_IN_CATCH,
+ "Cannot use optional parameters in catch."),
- static const MessageKind THROW_WITHOUT_EXPRESSION = const MessageKind(
- "Cannot use re-throw outside of catch block "
- "(expression expected after 'throw').");
+ MessageKind.THROW_WITHOUT_EXPRESSION:
+ const MessageTemplate(MessageKind.THROW_WITHOUT_EXPRESSION,
+ "Cannot use re-throw outside of catch block "
+ "(expression expected after 'throw')."),
- static const MessageKind UNBOUND_LABEL = const MessageKind(
- "Cannot resolve label '#{labelName}'.");
+ MessageKind.UNBOUND_LABEL:
+ const MessageTemplate(MessageKind.UNBOUND_LABEL,
+ "Cannot resolve label '#{labelName}'."),
- static const MessageKind NO_BREAK_TARGET = const MessageKind(
- "'break' statement not inside switch or loop.");
+ MessageKind.NO_BREAK_TARGET:
+ const MessageTemplate(MessageKind.NO_BREAK_TARGET,
+ "'break' statement not inside switch or loop."),
- static const MessageKind NO_CONTINUE_TARGET = const MessageKind(
- "'continue' statement not inside loop.");
+ MessageKind.NO_CONTINUE_TARGET:
+ const MessageTemplate(MessageKind.NO_CONTINUE_TARGET,
+ "'continue' statement not inside loop."),
- static const MessageKind EXISTING_LABEL = const MessageKind(
- "Original declaration of duplicate label '#{labelName}'.");
+ MessageKind.EXISTING_LABEL:
+ const MessageTemplate(MessageKind.EXISTING_LABEL,
+ "Original declaration of duplicate label '#{labelName}'."),
- static const MessageKind DUPLICATE_LABEL = const MessageKind(
- "Duplicate declaration of label '#{labelName}'.");
+ MessageKind.DUPLICATE_LABEL:
+ const MessageTemplate(MessageKind.DUPLICATE_LABEL,
+ "Duplicate declaration of label '#{labelName}'."),
- static const MessageKind UNUSED_LABEL = const MessageKind(
- "Unused label '#{labelName}'.");
+ MessageKind.UNUSED_LABEL:
+ const MessageTemplate(MessageKind.UNUSED_LABEL,
+ "Unused label '#{labelName}'."),
- static const MessageKind INVALID_CONTINUE = const MessageKind(
- "Target of continue is not a loop or switch case.");
+ MessageKind.INVALID_CONTINUE:
+ const MessageTemplate(MessageKind.INVALID_CONTINUE,
+ "Target of continue is not a loop or switch case."),
- static const MessageKind INVALID_BREAK = const MessageKind(
- "Target of break is not a statement.");
+ MessageKind.INVALID_BREAK:
+ const MessageTemplate(MessageKind.INVALID_BREAK,
+ "Target of break is not a statement."),
- static const MessageKind DUPLICATE_TYPE_VARIABLE_NAME = const MessageKind(
- "Type variable '#{typeVariableName}' already declared.");
+ MessageKind.DUPLICATE_TYPE_VARIABLE_NAME:
+ const MessageTemplate(MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
+ "Type variable '#{typeVariableName}' already declared."),
- static const MessageKind TYPE_VARIABLE_WITHIN_STATIC_MEMBER =
- const MessageKind(
- "Cannot refer to type variable '#{typeVariableName}' "
- "within a static member.");
+ MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER:
+ const MessageTemplate(MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
+ "Cannot refer to type variable '#{typeVariableName}' "
+ "within a static member."),
- static const MessageKind TYPE_VARIABLE_IN_CONSTANT = const MessageKind(
- "Constant expressions can't refer to type variables.",
- howToFix: "Try removing the type variable or replacing it with a "
- "concrete type.",
- examples: const ["""
+ MessageKind.TYPE_VARIABLE_IN_CONSTANT:
+ const MessageTemplate(MessageKind.TYPE_VARIABLE_IN_CONSTANT,
+ "Constant expressions can't refer to type variables.",
+ howToFix: "Try removing the type variable or replacing it with a "
+ "concrete type.",
+ examples: const ["""
class C<T> {
const C();
@@ -603,74 +1080,88 @@
void main() => new C().m(null);
"""
-]);
+]),
-
- static const MessageKind INVALID_TYPE_VARIABLE_BOUND = const MessageKind(
- "'#{typeArgument}' is not a subtype of bound '#{bound}' for "
- "type variable '#{typeVariable}' of type '#{thisType}'.",
- howToFix: "Try to change or remove the type argument.",
- examples: const ["""
+ MessageKind.INVALID_TYPE_VARIABLE_BOUND:
+ const MessageTemplate(MessageKind.INVALID_TYPE_VARIABLE_BOUND,
+ "'#{typeArgument}' is not a subtype of bound '#{bound}' for "
+ "type variable '#{typeVariable}' of type '#{thisType}'.",
+ howToFix: "Try to change or remove the type argument.",
+ examples: const ["""
class C<T extends num> {}
// 'String' is not a valid instantiation of T with bound num.'.
main() => new C<String>();
-"""]);
+"""]),
- static const MessageKind INVALID_USE_OF_SUPER = const MessageKind(
- "'super' not allowed here.");
+ MessageKind.INVALID_USE_OF_SUPER:
+ const MessageTemplate(MessageKind.INVALID_USE_OF_SUPER,
+ "'super' not allowed here."),
- static const MessageKind INVALID_CASE_DEFAULT = const MessageKind(
- "'default' only allowed on last case of a switch.");
+ MessageKind.INVALID_CASE_DEFAULT:
+ const MessageTemplate(MessageKind.INVALID_CASE_DEFAULT,
+ "'default' only allowed on last case of a switch."),
- static const MessageKind SWITCH_CASE_TYPES_NOT_EQUAL = const MessageKind(
- "'case' expressions do not all have type '#{type}'.");
+ MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL:
+ const MessageTemplate(MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
+ "'case' expressions do not all have type '#{type}'."),
- static const MessageKind SWITCH_CASE_TYPES_NOT_EQUAL_CASE = const MessageKind(
- "'case' expression of type '#{type}'.");
+ MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE:
+ const MessageTemplate(MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
+ "'case' expression of type '#{type}'."),
- static const MessageKind SWITCH_CASE_FORBIDDEN = const MessageKind(
- "'case' expression may not be of type '#{type}'.");
+ MessageKind.SWITCH_CASE_FORBIDDEN:
+ const MessageTemplate(MessageKind.SWITCH_CASE_FORBIDDEN,
+ "'case' expression may not be of type '#{type}'."),
- static const MessageKind SWITCH_CASE_VALUE_OVERRIDES_EQUALS =
- const MessageKind(
- "'case' expression type '#{type}' overrides 'operator =='.");
+ MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS:
+ const MessageTemplate(MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
+ "'case' expression type '#{type}' overrides 'operator =='."),
- static const MessageKind INVALID_ARGUMENT_AFTER_NAMED = const MessageKind(
- "Unnamed argument after named argument.");
+ MessageKind.INVALID_ARGUMENT_AFTER_NAMED:
+ const MessageTemplate(MessageKind.INVALID_ARGUMENT_AFTER_NAMED,
+ "Unnamed argument after named argument."),
- static const MessageKind NOT_A_COMPILE_TIME_CONSTANT = const MessageKind(
- "Not a compile-time constant.");
+ MessageKind.NOT_A_COMPILE_TIME_CONSTANT:
+ const MessageTemplate(MessageKind.NOT_A_COMPILE_TIME_CONSTANT,
+ "Not a compile-time constant."),
- static const MessageKind DEFERRED_COMPILE_TIME_CONSTANT = const MessageKind(
- "A deferred value cannot be used as a compile-time constant.");
+ MessageKind.DEFERRED_COMPILE_TIME_CONSTANT:
+ const MessageTemplate(MessageKind.DEFERRED_COMPILE_TIME_CONSTANT,
+ "A deferred value cannot be used as a compile-time constant."),
- static const MessageKind DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION =
- const MessageKind(
+ MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION:
+ const MessageTemplate(
+ MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION,
"A deferred class cannot be used to create a "
- "compile-time constant.");
+ "compile-time constant."),
- static const MessageKind CYCLIC_COMPILE_TIME_CONSTANTS = const MessageKind(
- "Cycle in the compile-time constant computation.");
+ MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS:
+ const MessageTemplate(MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS,
+ "Cycle in the compile-time constant computation."),
- static const MessageKind CONSTRUCTOR_IS_NOT_CONST = const MessageKind(
- "Constructor is not a 'const' constructor.");
+ MessageKind.CONSTRUCTOR_IS_NOT_CONST:
+ const MessageTemplate(MessageKind.CONSTRUCTOR_IS_NOT_CONST,
+ "Constructor is not a 'const' constructor."),
- static const MessageKind CONST_MAP_KEY_OVERRIDES_EQUALS =
- const MessageKind(
- "Const-map key type '#{type}' overrides 'operator =='.");
+ MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS:
+ const MessageTemplate(MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
+ "Const-map key type '#{type}' overrides 'operator =='."),
- static const MessageKind NO_SUCH_LIBRARY_MEMBER = const MessageKind(
- "'#{libraryName}' has no member named '#{memberName}'.");
+ MessageKind.NO_SUCH_LIBRARY_MEMBER:
+ const MessageTemplate(MessageKind.NO_SUCH_LIBRARY_MEMBER,
+ "'#{libraryName}' has no member named '#{memberName}'."),
- static const MessageKind CANNOT_INSTANTIATE_TYPEDEF = const MessageKind(
- "Cannot instantiate typedef '#{typedefName}'.");
+ MessageKind.CANNOT_INSTANTIATE_TYPEDEF:
+ const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
+ "Cannot instantiate typedef '#{typedefName}'."),
- static const MessageKind REQUIRED_PARAMETER_WITH_DEFAULT = const MessageKind(
- "Non-optional parameters can't have a default value.",
- howToFix:
- "Try removing the default value or making the parameter optional.",
- examples: const ["""
+ MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT,
+ "Non-optional parameters can't have a default value.",
+ howToFix:
+ "Try removing the default value or making the parameter optional.",
+ examples: const ["""
main() {
foo(a: 1) => print(a);
foo(2);
@@ -678,33 +1169,36 @@
main() {
foo(a = 1) => print(a);
foo(2);
-}"""]);
+}"""]),
- static const MessageKind NAMED_PARAMETER_WITH_EQUALS = const MessageKind(
- "Named optional parameters can't use '=' to specify a default "
- "value.",
- howToFix: "Try replacing '=' with ':'.",
- examples: const ["""
+ MessageKind.NAMED_PARAMETER_WITH_EQUALS:
+ const MessageTemplate(MessageKind.NAMED_PARAMETER_WITH_EQUALS,
+ "Named optional parameters can't use '=' to specify a default "
+ "value.",
+ howToFix: "Try replacing '=' with ':'.",
+ examples: const ["""
main() {
foo({a = 1}) => print(a);
foo(a: 2);
-}"""]);
+}"""]),
- static const MessageKind POSITIONAL_PARAMETER_WITH_EQUALS = const MessageKind(
- "Positional optional parameters can't use ':' to specify a "
- "default value.",
- howToFix: "Try replacing ':' with '='.",
- examples: const ["""
+ MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS:
+ const MessageTemplate(MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS,
+ "Positional optional parameters can't use ':' to specify a "
+ "default value.",
+ howToFix: "Try replacing ':' with '='.",
+ examples: const ["""
main() {
foo([a: 1]) => print(a);
foo(2);
-}"""]);
+}"""]),
- static const MessageKind TYPEDEF_FORMAL_WITH_DEFAULT = const MessageKind(
- "A parameter of a typedef can't specify a default value.",
- howToFix:
- "Try removing the default value.",
- examples: const ["""
+ MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT,
+ "A parameter of a typedef can't specify a default value.",
+ howToFix:
+ "Try removing the default value.",
+ examples: const ["""
typedef void F([int arg = 0]);
main() {
@@ -714,13 +1208,14 @@
main() {
F f;
-}"""]);
+}"""]),
- static const MessageKind FUNCTION_TYPE_FORMAL_WITH_DEFAULT = const MessageKind(
- "A function type parameter can't specify a default value.",
- howToFix:
- "Try removing the default value.",
- examples: const ["""
+ MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT,
+ "A function type parameter can't specify a default value.",
+ howToFix:
+ "Try removing the default value.",
+ examples: const ["""
foo(f(int i, [a = 1])) {}
main() {
@@ -730,14 +1225,15 @@
main() {
foo(1, a: 2);
-}"""]);
+}"""]),
- static const MessageKind REDIRECTING_FACTORY_WITH_DEFAULT = const MessageKind(
- "A parameter of a redirecting factory constructor can't specify a "
- "default value.",
- howToFix:
- "Try removing the default value.",
- examples: const ["""
+ MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT:
+ const MessageTemplate(MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT,
+ "A parameter of a redirecting factory constructor can't specify a "
+ "default value.",
+ howToFix:
+ "Try removing the default value.",
+ examples: const ["""
class A {
A([a]);
factory A.foo([a = 1]) = A;
@@ -753,12 +1249,13 @@
main() {
new A.foo(a: 1);
-}"""]);
+}"""]),
- static const MessageKind FORMAL_DECLARED_CONST = const MessageKind(
- "A formal parameter can't be declared const.",
- howToFix: "Try removing 'const'.",
- examples: const ["""
+ MessageKind.FORMAL_DECLARED_CONST:
+ const MessageTemplate(MessageKind.FORMAL_DECLARED_CONST,
+ "A formal parameter can't be declared const.",
+ howToFix: "Try removing 'const'.",
+ examples: const ["""
foo(const x) {}
main() => foo(42);
""", """
@@ -767,12 +1264,13 @@
""", """
foo([const x]) {}
main() => foo(42);
-"""]);
+"""]),
- static const MessageKind FORMAL_DECLARED_STATIC = const MessageKind(
- "A formal parameter can't be declared static.",
- howToFix: "Try removing 'static'.",
- examples: const ["""
+ MessageKind.FORMAL_DECLARED_STATIC:
+ const MessageTemplate(MessageKind.FORMAL_DECLARED_STATIC,
+ "A formal parameter can't be declared static.",
+ howToFix: "Try removing 'static'.",
+ examples: const ["""
foo(static x) {}
main() => foo(42);
""", """
@@ -781,12 +1279,13 @@
""", """
foo([static x]) {}
main() => foo(42);
-"""]);
+"""]),
- static const MessageKind FINAL_FUNCTION_TYPE_PARAMETER = const MessageKind(
- "A function type parameter can't be declared final.",
- howToFix: "Try removing 'final'.",
- examples: const ["""
+ MessageKind.FINAL_FUNCTION_TYPE_PARAMETER:
+ const MessageTemplate(MessageKind.FINAL_FUNCTION_TYPE_PARAMETER,
+ "A function type parameter can't be declared final.",
+ howToFix: "Try removing 'final'.",
+ examples: const ["""
foo(final int x(int a)) {}
main() => foo((y) => 42);
""", """
@@ -795,12 +1294,13 @@
""", """
foo([final int x(int a)]) {}
main() => foo((y) => 42);
-"""]);
+"""]),
- static const MessageKind VAR_FUNCTION_TYPE_PARAMETER = const MessageKind(
- "A function type parameter can't be declared with 'var'.",
- howToFix: "Try removing 'var'.",
- examples: const ["""
+ MessageKind.VAR_FUNCTION_TYPE_PARAMETER:
+ const MessageTemplate(MessageKind.VAR_FUNCTION_TYPE_PARAMETER,
+ "A function type parameter can't be declared with 'var'.",
+ howToFix: "Try removing 'var'.",
+ examples: const ["""
foo(var int x(int a)) {}
main() => foo((y) => 42);
""", """
@@ -809,27 +1309,32 @@
""", """
foo([var int x(int a)]) {}
main() => foo((y) => 42);
-"""]);
+"""]),
- static const MessageKind CANNOT_INSTANTIATE_TYPE_VARIABLE = const MessageKind(
- "Cannot instantiate type variable '#{typeVariableName}'.");
+ MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE:
+ const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
+ "Cannot instantiate type variable '#{typeVariableName}'."),
- static const MessageKind CYCLIC_TYPE_VARIABLE = const MessageKind(
- "Type variable '#{typeVariableName}' is a supertype of itself.");
+ MessageKind.CYCLIC_TYPE_VARIABLE:
+ const MessageTemplate(MessageKind.CYCLIC_TYPE_VARIABLE,
+ "Type variable '#{typeVariableName}' is a supertype of itself."),
- static const CYCLIC_TYPEDEF = const MessageKind(
- "A typedef can't refer to itself.",
- howToFix: "Try removing all references to '#{typedefName}' "
- "in the definition of '#{typedefName}'.",
- examples: const ["""
+ MessageKind.CYCLIC_TYPEDEF:
+ const MessageTemplate(MessageKind.CYCLIC_TYPEDEF,
+ "A typedef can't refer to itself.",
+ howToFix: "Try removing all references to '#{typedefName}' "
+ "in the definition of '#{typedefName}'.",
+ examples: const ["""
typedef F F(); // The return type 'F' is a self-reference.
-main() { F f = null; }"""]);
+main() { F f = null; }"""]),
- static const CYCLIC_TYPEDEF_ONE = const MessageKind(
- "A typedef can't refer to itself through another typedef.",
- howToFix: "Try removing all references to "
- "'#{otherTypedefName}' in the definition of '#{typedefName}'.",
- examples: const ["""
+ MessageKind.CYCLIC_TYPEDEF_ONE:
+ const MessageTemplate(MessageKind.CYCLIC_TYPEDEF_ONE,
+ "A typedef can't refer to itself through another typedef.",
+ howToFix:
+ "Try removing all references to "
+ "'#{otherTypedefName}' in the definition of '#{typedefName}'.",
+ examples: const ["""
typedef G F(); // The return type 'G' is a self-reference through typedef 'G'.
typedef F G(); // The return type 'F' is a self-reference through typedef 'F'.
main() { F f = null; }""",
@@ -837,49 +1342,59 @@
typedef G F(); // The return type 'G' creates a self-reference.
typedef H G(); // The return type 'H' creates a self-reference.
typedef H(F f); // The argument type 'F' creates a self-reference.
-main() { F f = null; }"""]);
+main() { F f = null; }"""]),
- static const MessageKind CLASS_NAME_EXPECTED = const MessageKind(
- "Class name expected.");
+ MessageKind.CLASS_NAME_EXPECTED:
+ const MessageTemplate(MessageKind.CLASS_NAME_EXPECTED,
+ "Class name expected."),
- static const MessageKind CANNOT_EXTEND = const MessageKind(
- "'#{type}' cannot be extended.");
+ MessageKind.CANNOT_EXTEND:
+ const MessageTemplate(MessageKind.CANNOT_EXTEND,
+ "'#{type}' cannot be extended."),
- static const MessageKind CANNOT_IMPLEMENT = const MessageKind(
- "'#{type}' cannot be implemented.");
+ MessageKind.CANNOT_IMPLEMENT:
+ const MessageTemplate(MessageKind.CANNOT_IMPLEMENT,
+ "'#{type}' cannot be implemented."),
- // TODO(johnnwinther): Split messages into reasons for malformedness.
- static const MessageKind CANNOT_EXTEND_MALFORMED = const MessageKind(
- "Class '#{className}' can't extend the type '#{malformedType}' because "
- "it is malformed.",
- howToFix: "Try correcting the malformed type annotation or removing the "
- "'extends' clause.",
- examples: const ["""
+ // TODO(johnnwinther): Split messages into reasons for malformedness.
+ MessageKind.CANNOT_EXTEND_MALFORMED:
+ const MessageTemplate(MessageKind.CANNOT_EXTEND_MALFORMED,
+ "Class '#{className}' can't extend the type '#{malformedType}' "
+ "because it is malformed.",
+ howToFix:
+ "Try correcting the malformed type annotation or removing the "
+ "'extends' clause.",
+ examples: const ["""
class A extends Malformed {}
-main() => new A();"""]);
+main() => new A();"""]),
- static const MessageKind CANNOT_IMPLEMENT_MALFORMED = const MessageKind(
- "Class '#{className}' can't implement the type '#{malformedType}' "
- "because it is malformed.",
- howToFix: "Try correcting the malformed type annotation or removing the "
- "type from the 'implements' clause.",
- examples: const ["""
+ MessageKind.CANNOT_IMPLEMENT_MALFORMED:
+ const MessageTemplate(MessageKind.CANNOT_IMPLEMENT_MALFORMED,
+ "Class '#{className}' can't implement the type '#{malformedType}' "
+ "because it is malformed.",
+ howToFix:
+ "Try correcting the malformed type annotation or removing the "
+ "type from the 'implements' clause.",
+ examples: const ["""
class A implements Malformed {}
-main() => new A();"""]);
+main() => new A();"""]),
- static const MessageKind CANNOT_MIXIN_MALFORMED = const MessageKind(
- "Class '#{className}' can't mixin the type '#{malformedType}' because it "
- "is malformed.",
- howToFix: "Try correcting the malformed type annotation or removing the "
- "type from the 'with' clause.",
- examples: const ["""
+ MessageKind.CANNOT_MIXIN_MALFORMED:
+ const MessageTemplate(MessageKind.CANNOT_MIXIN_MALFORMED,
+ "Class '#{className}' can't mixin the type '#{malformedType}' "
+ "because it is malformed.",
+ howToFix:
+ "Try correcting the malformed type annotation or removing the "
+ "type from the 'with' clause.",
+ examples: const ["""
class A extends Object with Malformed {}
-main() => new A();"""]);
+main() => new A();"""]),
- static const MessageKind CANNOT_MIXIN = const MessageKind(
- "The type '#{type}' can't be mixed in.",
- howToFix: "Try removing '#{type}' from the 'with' clause.",
- examples: const ["""
+ MessageKind.CANNOT_MIXIN:
+ const MessageTemplate(MessageKind.CANNOT_MIXIN,
+ "The type '#{type}' can't be mixed in.",
+ howToFix: "Try removing '#{type}' from the 'with' clause.",
+ examples: const ["""
class C extends Object with String {}
main() => new C();
@@ -887,60 +1402,66 @@
typedef C = Object with String;
main() => new C();
-"""]);
+"""]),
- static const MessageKind CANNOT_EXTEND_ENUM = const MessageKind(
- "Class '#{className}' can't extend the type '#{enumType}' because "
- "it is declared by an enum.",
- howToFix: "Try making '#{enumType}' a normal class or removing the "
- "'extends' clause.",
- examples: const ["""
+ MessageKind.CANNOT_EXTEND_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_EXTEND_ENUM,
+ "Class '#{className}' can't extend the type '#{enumType}' because "
+ "it is declared by an enum.",
+ howToFix: "Try making '#{enumType}' a normal class or removing the "
+ "'extends' clause.",
+ examples: const ["""
enum Enum { A }
class B extends Enum {}
-main() => new B();"""]);
+main() => new B();"""]),
- static const MessageKind CANNOT_IMPLEMENT_ENUM = const MessageKind(
- "Class '#{className}' can't implement the type '#{enumType}' "
- "because it is declared by an enum.",
- howToFix: "Try making '#{enumType}' a normal class or removing the "
- "type from the 'implements' clause.",
- examples: const ["""
+ MessageKind.CANNOT_IMPLEMENT_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_IMPLEMENT_ENUM,
+ "Class '#{className}' can't implement the type '#{enumType}' "
+ "because it is declared by an enum.",
+ howToFix: "Try making '#{enumType}' a normal class or removing the "
+ "type from the 'implements' clause.",
+ examples: const ["""
enum Enum { A }
class B implements Enum {}
-main() => new B();"""]);
+main() => new B();"""]),
- static const MessageKind CANNOT_MIXIN_ENUM = const MessageKind(
- "Class '#{className}' can't mixin the type '#{enumType}' because it "
- "is declared by an enum.",
- howToFix: "Try making '#{enumType}' a normal class or removing the "
- "type from the 'with' clause.",
- examples: const ["""
+ MessageKind.CANNOT_MIXIN_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_MIXIN_ENUM,
+ "Class '#{className}' can't mixin the type '#{enumType}' because it "
+ "is declared by an enum.",
+ howToFix: "Try making '#{enumType}' a normal class or removing the "
+ "type from the 'with' clause.",
+ examples: const ["""
enum Enum { A }
class B extends Object with Enum {}
-main() => new B();"""]);
+main() => new B();"""]),
- static const MessageKind CANNOT_INSTANTIATE_ENUM = const MessageKind(
- "Enum type '#{enumName}' cannot be instantiated.",
- howToFix: "Try making '#{enumType}' a normal class or use an enum "
- "constant.",
- examples: const ["""
+ MessageKind.CANNOT_INSTANTIATE_ENUM:
+ const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_ENUM,
+ "Enum type '#{enumName}' cannot be instantiated.",
+ howToFix: "Try making '#{enumType}' a normal class or use an enum "
+ "constant.",
+ examples: const ["""
enum Enum { A }
main() => new Enum(0);""", """
enum Enum { A }
-main() => const Enum(0);"""]);
+main() => const Enum(0);"""]),
- static const MessageKind EMPTY_ENUM_DECLARATION = const MessageKind(
- "Enum '#{enumName}' must contain at least one value.",
- howToFix: "Try adding an enum constant or making #{enumName} a "
- "normal class.",
- examples: const ["""
+ MessageKind.EMPTY_ENUM_DECLARATION:
+ const MessageTemplate(MessageKind.EMPTY_ENUM_DECLARATION,
+ "Enum '#{enumName}' must contain at least one value.",
+ howToFix: "Try adding an enum constant or making #{enumName} a "
+ "normal class.",
+ examples: const ["""
enum Enum {}
-main() { Enum e; }"""]);
+main() { Enum e; }"""]),
- static const MessageKind MISSING_ENUM_CASES = const MessageKind(
- "Missing enum constants in switch statement: #{enumValues}.",
- howToFix: "Try adding the missing constants or a default case.",
- examples: const ["""
+ MessageKind.MISSING_ENUM_CASES:
+ const MessageTemplate(MessageKind.MISSING_ENUM_CASES,
+ "Missing enum constants in switch statement: #{enumValues}.",
+ howToFix: "Try adding the missing constants or a default case.",
+ examples: const ["""
enum Enum { A, B }
main() {
switch (Enum.A) {
@@ -952,283 +1473,343 @@
switch (Enum.A) {
case Enum.B: break;
}
-}"""]);
+}"""]),
- static const MessageKind DUPLICATE_EXTENDS_IMPLEMENTS = const MessageKind(
- "'#{type}' can not be both extended and implemented.");
+ MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS:
+ const MessageTemplate(MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
+ "'#{type}' can not be both extended and implemented."),
- static const MessageKind DUPLICATE_IMPLEMENTS = const MessageKind(
- "'#{type}' must not occur more than once "
- "in the implements clause.");
+ MessageKind.DUPLICATE_IMPLEMENTS:
+ const MessageTemplate(MessageKind.DUPLICATE_IMPLEMENTS,
+ "'#{type}' must not occur more than once "
+ "in the implements clause."),
- static const MessageKind MULTI_INHERITANCE = const MessageKind(
- "Dart2js does not currently support inheritance of the same class with "
- "different type arguments: Both #{firstType} and #{secondType} are "
- "supertypes of #{thisType}.");
+ MessageKind.MULTI_INHERITANCE:
+ const MessageTemplate(MessageKind.MULTI_INHERITANCE,
+ "Dart2js does not currently support inheritance of the same class "
+ "with different type arguments: Both #{firstType} and #{secondType} "
+ "are supertypes of #{thisType}."),
- static const MessageKind ILLEGAL_SUPER_SEND = const MessageKind(
- "'#{name}' cannot be called on super.");
+ MessageKind.ILLEGAL_SUPER_SEND:
+ const MessageTemplate(MessageKind.ILLEGAL_SUPER_SEND,
+ "'#{name}' cannot be called on super."),
- static const MessageKind NO_SUCH_SUPER_MEMBER = const MessageKind(
- "Cannot resolve '#{memberName}' in a superclass of '#{className}'.");
+ MessageKind.NO_SUCH_SUPER_MEMBER:
+ const MessageTemplate(MessageKind.NO_SUCH_SUPER_MEMBER,
+ "Cannot resolve '#{memberName}' in a superclass of '#{className}'."),
- static const MessageKind ADDITIONAL_TYPE_ARGUMENT = const MessageKind(
- "Additional type argument.");
+ MessageKind.ADDITIONAL_TYPE_ARGUMENT:
+ const MessageTemplate(MessageKind.ADDITIONAL_TYPE_ARGUMENT,
+ "Additional type argument."),
- static const MessageKind MISSING_TYPE_ARGUMENT = const MessageKind(
- "Missing type argument.");
+ MessageKind.MISSING_TYPE_ARGUMENT:
+ const MessageTemplate(MessageKind.MISSING_TYPE_ARGUMENT,
+ "Missing type argument."),
- // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or MISSING_TYPE_ARGUMENT
- // instead.
- static const MessageKind TYPE_ARGUMENT_COUNT_MISMATCH = const MessageKind(
- "Incorrect number of type arguments on '#{type}'.");
+ // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or
+ // MISSING_TYPE_ARGUMENT instead.
+ MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH:
+ const MessageTemplate(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
+ "Incorrect number of type arguments on '#{type}'."),
- static const MessageKind GETTER_MISMATCH = const MessageKind(
- "Setter disagrees on: '#{modifiers}'.");
+ MessageKind.GETTER_MISMATCH:
+ const MessageTemplate(MessageKind.GETTER_MISMATCH,
+ "Setter disagrees on: '#{modifiers}'."),
- static const MessageKind SETTER_MISMATCH = const MessageKind(
- "Getter disagrees on: '#{modifiers}'.");
+ MessageKind.SETTER_MISMATCH:
+ const MessageTemplate(MessageKind.SETTER_MISMATCH,
+ "Getter disagrees on: '#{modifiers}'."),
- static const MessageKind ILLEGAL_SETTER_FORMALS = const MessageKind(
- "A setter must have exactly one argument.");
+ MessageKind.ILLEGAL_SETTER_FORMALS:
+ const MessageTemplate(MessageKind.ILLEGAL_SETTER_FORMALS,
+ "A setter must have exactly one argument."),
- static const MessageKind NO_STATIC_OVERRIDE = const MessageKind(
- "Static member cannot override instance member '#{memberName}' of "
- "'#{className}'.");
+ MessageKind.NO_STATIC_OVERRIDE:
+ const MessageTemplate(MessageKind.NO_STATIC_OVERRIDE,
+ "Static member cannot override instance member '#{memberName}' of "
+ "'#{className}'."),
- static const MessageKind NO_STATIC_OVERRIDE_CONT = const MessageKind(
- "This is the instance member that cannot be overridden "
- "by a static member.");
+ MessageKind.NO_STATIC_OVERRIDE_CONT:
+ const MessageTemplate(MessageKind.NO_STATIC_OVERRIDE_CONT,
+ "This is the instance member that cannot be overridden "
+ "by a static member."),
- static const MessageKind INSTANCE_STATIC_SAME_NAME = const MessageKind(
- "Instance member '#{memberName}' and static member of "
- "superclass '#{className}' have the same name.");
+ MessageKind.INSTANCE_STATIC_SAME_NAME:
+ const MessageTemplate(MessageKind.INSTANCE_STATIC_SAME_NAME,
+ "Instance member '#{memberName}' and static member of "
+ "superclass '#{className}' have the same name."),
- static const MessageKind INSTANCE_STATIC_SAME_NAME_CONT = const MessageKind(
- "This is the static member with the same name.");
+ MessageKind.INSTANCE_STATIC_SAME_NAME_CONT:
+ const MessageTemplate(MessageKind.INSTANCE_STATIC_SAME_NAME_CONT,
+ "This is the static member with the same name."),
- static const MessageKind INVALID_OVERRIDE_METHOD = const MessageKind(
- "The type '#{declaredType}' of method '#{name}' declared in "
- "'#{class}' is not a subtype of the overridden method type "
- "'#{inheritedType}' inherited from '#{inheritedClass}'.");
+ MessageKind.INVALID_OVERRIDE_METHOD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_METHOD,
+ "The type '#{declaredType}' of method '#{name}' declared in "
+ "'#{class}' is not a subtype of the overridden method type "
+ "'#{inheritedType}' inherited from '#{inheritedClass}'."),
- static const MessageKind INVALID_OVERRIDDEN_METHOD = const MessageKind(
- "This is the overridden method '#{name}' declared in class "
- "'#{class}'.");
+ MessageKind.INVALID_OVERRIDDEN_METHOD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_METHOD,
+ "This is the overridden method '#{name}' declared in class "
+ "'#{class}'."),
- static const MessageKind INVALID_OVERRIDE_GETTER = const MessageKind(
- "The type '#{declaredType}' of getter '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden getter inherited from '#{inheritedClass}'.");
-
- static const MessageKind INVALID_OVERRIDDEN_GETTER = const MessageKind(
- "This is the overridden getter '#{name}' declared in class "
- "'#{class}'.");
-
- static const MessageKind INVALID_OVERRIDE_GETTER_WITH_FIELD =
- const MessageKind(
- "The type '#{declaredType}' of field '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden getter inherited from '#{inheritedClass}'.");
-
- static const MessageKind INVALID_OVERRIDE_FIELD_WITH_GETTER =
- const MessageKind(
+ MessageKind.INVALID_OVERRIDE_GETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_GETTER,
"The type '#{declaredType}' of getter '#{name}' declared in "
"'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden field inherited from '#{inheritedClass}'.");
+ "overridden getter inherited from '#{inheritedClass}'."),
- static const MessageKind INVALID_OVERRIDE_SETTER = const MessageKind(
- "The type '#{declaredType}' of setter '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden setter inherited from '#{inheritedClass}'.");
+ MessageKind.INVALID_OVERRIDDEN_GETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_GETTER,
+ "This is the overridden getter '#{name}' declared in class "
+ "'#{class}'."),
- static const MessageKind INVALID_OVERRIDDEN_SETTER = const MessageKind(
- "This is the overridden setter '#{name}' declared in class "
- "'#{class}'.");
-
- static const MessageKind INVALID_OVERRIDE_SETTER_WITH_FIELD =
- const MessageKind(
+ MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD,
"The type '#{declaredType}' of field '#{name}' declared in "
"'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden setter inherited from '#{inheritedClass}'.");
+ "overridden getter inherited from '#{inheritedClass}'."),
- static const MessageKind INVALID_OVERRIDE_FIELD_WITH_SETTER =
- const MessageKind(
+ MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER,
+ "The type '#{declaredType}' of getter '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden field inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDE_SETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_SETTER,
"The type '#{declaredType}' of setter '#{name}' declared in "
"'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden field inherited from '#{inheritedClass}'.");
+ "overridden setter inherited from '#{inheritedClass}'."),
- static const MessageKind INVALID_OVERRIDE_FIELD = const MessageKind(
- "The type '#{declaredType}' of field '#{name}' declared in "
- "'#{class}' is not assignable to the type '#{inheritedType}' of the "
- "overridden field inherited from '#{inheritedClass}'.");
+ MessageKind.INVALID_OVERRIDDEN_SETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_SETTER,
+ "This is the overridden setter '#{name}' declared in class "
+ "'#{class}'."),
- static const MessageKind INVALID_OVERRIDDEN_FIELD = const MessageKind(
- "This is the overridden field '#{name}' declared in class "
- "'#{class}'.");
+ MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD,
+ "The type '#{declaredType}' of field '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden setter inherited from '#{inheritedClass}'."),
- static const MessageKind CANNOT_OVERRIDE_FIELD_WITH_METHOD =
- const MessageKind(
+ MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER,
+ "The type '#{declaredType}' of setter '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden field inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDE_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD,
+ "The type '#{declaredType}' of field '#{name}' declared in "
+ "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+ "overridden field inherited from '#{inheritedClass}'."),
+
+ MessageKind.INVALID_OVERRIDDEN_FIELD:
+ const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_FIELD,
+ "This is the overridden field '#{name}' declared in class "
+ "'#{class}'."),
+
+ MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD:
+ const MessageTemplate(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD,
"Method '#{name}' in '#{class}' can't override field from "
- "'#{inheritedClass}'.");
+ "'#{inheritedClass}'."),
- static const MessageKind CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT =
- const MessageKind(
- "This is the field that cannot be overridden by a method.");
+ MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT,
+ "This is the field that cannot be overridden by a method."),
- static const MessageKind CANNOT_OVERRIDE_METHOD_WITH_FIELD =
- const MessageKind(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD,
"Field '#{name}' in '#{class}' can't override method from "
- "'#{inheritedClass}'.");
+ "'#{inheritedClass}'."),
- static const MessageKind CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT =
- const MessageKind(
- "This is the method that cannot be overridden by a field.");
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT,
+ "This is the method that cannot be overridden by a field."),
- static const MessageKind CANNOT_OVERRIDE_GETTER_WITH_METHOD =
- const MessageKind(
- "Method '#{name}' in '#{class}' can't override getter from "
- "'#{inheritedClass}'.");
+ MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD:
+ const MessageTemplate(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD,
+ "Method '#{name}' in '#{class}' can't override getter from "
+ "'#{inheritedClass}'."),
- static const MessageKind CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT =
- const MessageKind(
- "This is the getter that cannot be overridden by a method.");
+ MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT,
+ "This is the getter that cannot be overridden by a method."),
- static const MessageKind CANNOT_OVERRIDE_METHOD_WITH_GETTER =
- const MessageKind(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER:
+ const MessageTemplate(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER,
"Getter '#{name}' in '#{class}' can't override method from "
- "'#{inheritedClass}'.");
+ "'#{inheritedClass}'."),
- static const MessageKind CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT =
- const MessageKind(
- "This is the method that cannot be overridden by a getter.");
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT:
+ const MessageTemplate(
+ MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT,
+ "This is the method that cannot be overridden by a getter."),
- static const MessageKind MISSING_FORMALS = const MessageKind(
- "Formal parameters are missing.");
+ MessageKind.MISSING_FORMALS:
+ const MessageTemplate(MessageKind.MISSING_FORMALS,
+ "Formal parameters are missing."),
- static const MessageKind EXTRA_FORMALS = const MessageKind(
- "Formal parameters are not allowed here.");
+ MessageKind.EXTRA_FORMALS:
+ const MessageTemplate(MessageKind.EXTRA_FORMALS,
+ "Formal parameters are not allowed here."),
- static const MessageKind UNARY_OPERATOR_BAD_ARITY = const MessageKind(
- "Operator '#{operatorName}' must have no parameters.");
+ MessageKind.UNARY_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.UNARY_OPERATOR_BAD_ARITY,
+ "Operator '#{operatorName}' must have no parameters."),
- static const MessageKind MINUS_OPERATOR_BAD_ARITY = const MessageKind(
- "Operator '-' must have 0 or 1 parameters.");
+ MessageKind.MINUS_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.MINUS_OPERATOR_BAD_ARITY,
+ "Operator '-' must have 0 or 1 parameters."),
- static const MessageKind BINARY_OPERATOR_BAD_ARITY = const MessageKind(
- "Operator '#{operatorName}' must have exactly 1 parameter.");
+ MessageKind.BINARY_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.BINARY_OPERATOR_BAD_ARITY,
+ "Operator '#{operatorName}' must have exactly 1 parameter."),
- static const MessageKind TERNARY_OPERATOR_BAD_ARITY = const MessageKind(
- "Operator '#{operatorName}' must have exactly 2 parameters.");
+ MessageKind.TERNARY_OPERATOR_BAD_ARITY:
+ const MessageTemplate(MessageKind.TERNARY_OPERATOR_BAD_ARITY,
+ "Operator '#{operatorName}' must have exactly 2 parameters."),
- static const MessageKind OPERATOR_OPTIONAL_PARAMETERS = const MessageKind(
- "Operator '#{operatorName}' cannot have optional parameters.");
+ MessageKind.OPERATOR_OPTIONAL_PARAMETERS:
+ const MessageTemplate(MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
+ "Operator '#{operatorName}' cannot have optional parameters."),
- static const MessageKind OPERATOR_NAMED_PARAMETERS = const MessageKind(
- "Operator '#{operatorName}' cannot have named parameters.");
+ MessageKind.OPERATOR_NAMED_PARAMETERS:
+ const MessageTemplate(MessageKind.OPERATOR_NAMED_PARAMETERS,
+ "Operator '#{operatorName}' cannot have named parameters."),
- static const MessageKind CONSTRUCTOR_WITH_RETURN_TYPE = const MessageKind(
- "Cannot have return type for constructor.");
+ MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE:
+ const MessageTemplate(MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE,
+ "Cannot have return type for constructor."),
- static const MessageKind CANNOT_RETURN_FROM_CONSTRUCTOR = const MessageKind(
- "Constructors can't return values.",
- howToFix: "Remove the return statement or use a factory constructor.",
- examples: const ["""
+ MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR,
+ "Constructors can't return values.",
+ howToFix: "Remove the return statement or use a factory constructor.",
+ examples: const ["""
class C {
C() {
return 1;
}
}
-main() => new C();"""]);
+main() => new C();"""]),
- static const MessageKind ILLEGAL_FINAL_METHOD_MODIFIER = const MessageKind(
- "Cannot have final modifier on method.");
+ MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER:
+ const MessageTemplate(MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER,
+ "Cannot have final modifier on method."),
- static const MessageKind ILLEGAL_CONST_FIELD_MODIFIER = const MessageKind(
- "Cannot have const modifier on non-static field.",
- howToFix: "Try adding a static modifier, or removing the const modifier.",
- examples: const ["""
+ MessageKind.ILLEGAL_CONST_FIELD_MODIFIER:
+ const MessageTemplate(MessageKind.ILLEGAL_CONST_FIELD_MODIFIER,
+ "Cannot have const modifier on non-static field.",
+ howToFix:
+ "Try adding a static modifier, or removing the const modifier.",
+ examples: const ["""
class C {
const int a = 1;
}
-main() => new C();"""]);
+main() => new C();"""]),
- static const MessageKind ILLEGAL_CONSTRUCTOR_MODIFIERS = const MessageKind(
- "Illegal constructor modifiers: '#{modifiers}'.");
+ MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS:
+ const MessageTemplate(MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
+ "Illegal constructor modifiers: '#{modifiers}'."),
- static const MessageKind ILLEGAL_MIXIN_APPLICATION_MODIFIERS =
- const MessageKind(
- "Illegal mixin application modifiers: '#{modifiers}'.");
+ MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
+ "Illegal mixin application modifiers: '#{modifiers}'."),
- static const MessageKind ILLEGAL_MIXIN_SUPERCLASS = const MessageKind(
- "Class used as mixin must have Object as superclass.");
+ MessageKind.ILLEGAL_MIXIN_SUPERCLASS:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_SUPERCLASS,
+ "Class used as mixin must have Object as superclass."),
- static const MessageKind ILLEGAL_MIXIN_OBJECT = const MessageKind(
- "Cannot use Object as mixin.");
+ MessageKind.ILLEGAL_MIXIN_OBJECT:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_OBJECT,
+ "Cannot use Object as mixin."),
- static const MessageKind ILLEGAL_MIXIN_CONSTRUCTOR = const MessageKind(
- "Class used as mixin cannot have non-factory constructor.");
+ MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR,
+ "Class used as mixin cannot have non-factory constructor."),
- static const MessageKind ILLEGAL_MIXIN_CYCLE = const MessageKind(
- "Class used as mixin introduces mixin cycle: "
- "'#{mixinName1}' <-> '#{mixinName2}'.");
+ MessageKind.ILLEGAL_MIXIN_CYCLE:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_CYCLE,
+ "Class used as mixin introduces mixin cycle: "
+ "'#{mixinName1}' <-> '#{mixinName2}'."),
- static const MessageKind ILLEGAL_MIXIN_WITH_SUPER = const MessageKind(
- "Cannot use class '#{className}' as a mixin because it uses "
- "'super'.");
+ MessageKind.ILLEGAL_MIXIN_WITH_SUPER:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
+ "Cannot use class '#{className}' as a mixin because it uses "
+ "'super'."),
- static const MessageKind ILLEGAL_MIXIN_SUPER_USE = const MessageKind(
- "Use of 'super' in class used as mixin.");
+ MessageKind.ILLEGAL_MIXIN_SUPER_USE:
+ const MessageTemplate(MessageKind.ILLEGAL_MIXIN_SUPER_USE,
+ "Use of 'super' in class used as mixin."),
- static const MessageKind PARAMETER_NAME_EXPECTED = const MessageKind(
- "parameter name expected.");
+ MessageKind.PARAMETER_NAME_EXPECTED:
+ const MessageTemplate(MessageKind.PARAMETER_NAME_EXPECTED,
+ "parameter name expected."),
- static const MessageKind CANNOT_RESOLVE_GETTER = const MessageKind(
- "Cannot resolve getter.");
+ MessageKind.CANNOT_RESOLVE_GETTER:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_GETTER,
+ "Cannot resolve getter."),
- static const MessageKind CANNOT_RESOLVE_SETTER = const MessageKind(
- "Cannot resolve setter.");
+ MessageKind.CANNOT_RESOLVE_SETTER:
+ const MessageTemplate(MessageKind.CANNOT_RESOLVE_SETTER,
+ "Cannot resolve setter."),
- static const MessageKind ASSIGNING_METHOD = const MessageKind(
- "Cannot assign a value to a method.");
+ MessageKind.ASSIGNING_METHOD:
+ const MessageTemplate(MessageKind.ASSIGNING_METHOD,
+ "Cannot assign a value to a method."),
- static const MessageKind ASSIGNING_METHOD_IN_SUPER = const MessageKind(
- "Cannot assign a value to method '#{name}' "
- "in superclass '#{superclassName}'.");
+ MessageKind.ASSIGNING_METHOD_IN_SUPER:
+ const MessageTemplate(MessageKind.ASSIGNING_METHOD_IN_SUPER,
+ "Cannot assign a value to method '#{name}' "
+ "in superclass '#{superclassName}'."),
- static const MessageKind ASSIGNING_TYPE = const MessageKind(
- "Cannot assign a value to a type.");
+ MessageKind.ASSIGNING_TYPE:
+ const MessageTemplate(MessageKind.ASSIGNING_TYPE,
+ "Cannot assign a value to a type."),
- static const MessageKind IF_NULL_ASSIGNING_TYPE = const MessageKind(
- "Cannot assign a value to a type. Note that types are never null, "
- "so this ??= assignment has no effect.",
- howToFix: "Try removing the '??=' assignment.",
- examples: const [
- "class A {} main() { print(A ??= 3);}",
- ]);
+ MessageKind.IF_NULL_ASSIGNING_TYPE:
+ const MessageTemplate(MessageKind.IF_NULL_ASSIGNING_TYPE,
+ "Cannot assign a value to a type. Note that types are never null, "
+ "so this ??= assignment has no effect.",
+ howToFix: "Try removing the '??=' assignment.",
+ examples: const [
+ "class A {} main() { print(A ??= 3);}",
+ ]),
- static const MessageKind VOID_NOT_ALLOWED = const MessageKind(
- "Type 'void' can't be used here because it isn't a return type.",
- howToFix: "Try removing 'void' keyword or replace it with 'var', 'final',"
- " or a type.",
- examples: const [
- "void x; main() {}",
- "foo(void x) {} main() { foo(null); }",
- ]);
+ MessageKind.VOID_NOT_ALLOWED:
+ const MessageTemplate(MessageKind.VOID_NOT_ALLOWED,
+ "Type 'void' can't be used here because it isn't a return type.",
+ howToFix:
+ "Try removing 'void' keyword or replace it with 'var', 'final', "
+ "or a type.",
+ examples: const [
+ "void x; main() {}",
+ "foo(void x) {} main() { foo(null); }",
+ ]),
- static const MessageKind NULL_NOT_ALLOWED = const MessageKind(
- "`null` can't be used here.");
+ MessageKind.NULL_NOT_ALLOWED:
+ const MessageTemplate(MessageKind.NULL_NOT_ALLOWED,
+ "`null` can't be used here."),
- static const MessageKind BEFORE_TOP_LEVEL = const MessageKind(
- "Part header must come before top-level definitions.");
+ MessageKind.BEFORE_TOP_LEVEL:
+ const MessageTemplate(MessageKind.BEFORE_TOP_LEVEL,
+ "Part header must come before top-level definitions."),
- static const MessageKind IMPORT_PART_OF = const MessageKind(
- "The imported library must not have a 'part-of' directive.",
- howToFix: "Try removing the 'part-of' directive or replacing the "
- "import of the library with a 'part' directive.",
- examples: const [const {
+ MessageKind.IMPORT_PART_OF:
+ const MessageTemplate(MessageKind.IMPORT_PART_OF,
+ "The imported library must not have a 'part-of' directive.",
+ howToFix: "Try removing the 'part-of' directive or replacing the "
+ "import of the library with a 'part' directive.",
+ examples: const [const {
'main.dart': """
library library;
@@ -1239,12 +1820,13 @@
'part.dart': """
part of library;
-"""}]);
+"""}]),
- static const MessageKind LIBRARY_NAME_MISMATCH = const MessageKind(
- "Expected part of library name '#{libraryName}'.",
- howToFix: "Try changing the directive to 'part of #{libraryName};'.",
- examples: const [const {
+ MessageKind.LIBRARY_NAME_MISMATCH:
+ const MessageTemplate(MessageKind.LIBRARY_NAME_MISMATCH,
+ "Expected part of library name '#{libraryName}'.",
+ howToFix: "Try changing the directive to 'part of #{libraryName};'.",
+ examples: const [const {
'main.dart': """
library lib.foo;
@@ -1255,13 +1837,14 @@
'part.dart': """
part of lib.bar;
-"""}]);
+"""}]),
- static const MessageKind MISSING_LIBRARY_NAME = const MessageKind(
- "Library has no name. Part directive expected library name "
- "to be '#{libraryName}'.",
- howToFix: "Try adding 'library #{libraryName};' to the library.",
- examples: const [const {
+ MessageKind.MISSING_LIBRARY_NAME:
+ const MessageTemplate(MessageKind.MISSING_LIBRARY_NAME,
+ "Library has no name. Part directive expected library name "
+ "to be '#{libraryName}'.",
+ howToFix: "Try adding 'library #{libraryName};' to the library.",
+ examples: const [const {
'main.dart': """
part 'part.dart';
@@ -1270,74 +1853,85 @@
'part.dart': """
part of lib.foo;
-"""}]);
+"""}]),
- static const MessageKind THIS_IS_THE_PART_OF_TAG = const MessageKind(
- "This is the part of directive.");
+ MessageKind.THIS_IS_THE_PART_OF_TAG:
+ const MessageTemplate(MessageKind.THIS_IS_THE_PART_OF_TAG,
+ "This is the part of directive."),
- static const MessageKind MISSING_PART_OF_TAG = const MessageKind(
- "This file has no part-of tag, but it is being used as a part.");
+ MessageKind.MISSING_PART_OF_TAG:
+ const MessageTemplate(MessageKind.MISSING_PART_OF_TAG,
+ "This file has no part-of tag, but it is being used as a part."),
- static const MessageKind DUPLICATED_PART_OF = const MessageKind(
- "Duplicated part-of directive.");
+ MessageKind.DUPLICATED_PART_OF:
+ const MessageTemplate(MessageKind.DUPLICATED_PART_OF,
+ "Duplicated part-of directive."),
- static const MessageKind DUPLICATED_LIBRARY_NAME = const MessageKind(
- "Duplicated library name '#{libraryName}'.");
+ MessageKind.DUPLICATED_LIBRARY_NAME:
+ const MessageTemplate(MessageKind.DUPLICATED_LIBRARY_NAME,
+ "Duplicated library name '#{libraryName}'."),
- static const MessageKind DUPLICATED_RESOURCE = const MessageKind(
- "The resource '#{resourceUri}' is loaded through both "
- "'#{canonicalUri1}' and '#{canonicalUri2}'.");
+ MessageKind.DUPLICATED_RESOURCE:
+ const MessageTemplate(MessageKind.DUPLICATED_RESOURCE,
+ "The resource '#{resourceUri}' is loaded through both "
+ "'#{canonicalUri1}' and '#{canonicalUri2}'."),
- static const MessageKind DUPLICATED_LIBRARY_RESOURCE =
- const MessageKind(
+ MessageKind.DUPLICATED_LIBRARY_RESOURCE:
+ const MessageTemplate(MessageKind.DUPLICATED_LIBRARY_RESOURCE,
"The library '#{libraryName}' in '#{resourceUri}' is loaded through "
- "both '#{canonicalUri1}' and '#{canonicalUri2}'.");
+ "both '#{canonicalUri1}' and '#{canonicalUri2}'."),
- // This is used as an exception.
- static const MessageKind INVALID_SOURCE_FILE_LOCATION = const MessageKind('''
+ // This is used as an exception.
+ MessageKind.INVALID_SOURCE_FILE_LOCATION:
+ const MessageTemplate(MessageKind.INVALID_SOURCE_FILE_LOCATION, '''
Invalid offset (#{offset}) in source map.
File: #{fileName}
-Length: #{length}''');
+Length: #{length}'''),
- static const MessageKind TOP_LEVEL_VARIABLE_DECLARED_STATIC =
- const MessageKind(
- "Top-level variable cannot be declared static.");
+ MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC:
+ const MessageTemplate(MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC,
+ "Top-level variable cannot be declared static."),
- static const MessageKind REFERENCE_IN_INITIALIZATION = const MessageKind(
- "Variable '#{variableName}' is referenced during its "
- "initialization.",
- howToFix: "If you are trying to reference a shadowed variable, rename"
- " one of the variables.",
- examples: const ["""
+ MessageKind.REFERENCE_IN_INITIALIZATION:
+ const MessageTemplate(MessageKind.REFERENCE_IN_INITIALIZATION,
+ "Variable '#{variableName}' is referenced during its "
+ "initialization.",
+ howToFix:
+ "If you are trying to reference a shadowed variable, rename "
+ "one of the variables.",
+ examples: const ["""
foo(t) {
var t = t;
return t;
}
main() => foo(1);
-"""]);
+"""]),
- static const MessageKind CONST_WITHOUT_INITIALIZER = const MessageKind(
- "A constant variable must be initialized.",
- howToFix: "Try adding an initializer or "
- "removing the 'const' modifier.",
- examples: const ["""
+ MessageKind.CONST_WITHOUT_INITIALIZER:
+ const MessageTemplate(MessageKind.CONST_WITHOUT_INITIALIZER,
+ "A constant variable must be initialized.",
+ howToFix: "Try adding an initializer or "
+ "removing the 'const' modifier.",
+ examples: const ["""
void main() {
const c; // This constant variable must be initialized.
-}"""]);
+}"""]),
- static const MessageKind FINAL_WITHOUT_INITIALIZER = const MessageKind(
- "A final variable must be initialized.",
- howToFix: "Try adding an initializer or "
- "removing the 'final' modifier.",
- examples: const [
- "class C { static final field; } main() => C.field;"]);
+ MessageKind.FINAL_WITHOUT_INITIALIZER:
+ const MessageTemplate(MessageKind.FINAL_WITHOUT_INITIALIZER,
+ "A final variable must be initialized.",
+ howToFix: "Try adding an initializer or "
+ "removing the 'final' modifier.",
+ examples: const [
+ "class C { static final field; } main() => C.field;"]),
- static const MessageKind MEMBER_USES_CLASS_NAME = const MessageKind(
- "Member variable can't have the same name as the class it is "
- "declared in.",
- howToFix: "Try renaming the variable.",
- examples: const ["""
+ MessageKind.MEMBER_USES_CLASS_NAME:
+ const MessageTemplate(MessageKind.MEMBER_USES_CLASS_NAME,
+ "Member variable can't have the same name as the class it is "
+ "declared in.",
+ howToFix: "Try renaming the variable.",
+ examples: const ["""
class A { var A; }
main() {
var a = new A();
@@ -1346,161 +1940,182 @@
""", """
class A { static var A; }
main() => A.A = 1;
-"""]);
+"""]),
- static const MessageKind WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT =
- const MessageKind(
+ MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT:
+ const MessageTemplate(
+ MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
"Wrong number of arguments to assert. Should be 1, but given "
- "#{argumentCount}.");
+ "#{argumentCount}."),
- static const MessageKind ASSERT_IS_GIVEN_NAMED_ARGUMENTS = const MessageKind(
- "'assert' takes no named arguments, but given #{argumentCount}.");
+ MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS:
+ const MessageTemplate(MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
+ "'assert' takes no named arguments, but given #{argumentCount}."),
- static const MessageKind FACTORY_REDIRECTION_IN_NON_FACTORY =
- const MessageKind(
- "Factory redirection only allowed in factories.");
+ MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY:
+ const MessageTemplate(MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY,
+ "Factory redirection only allowed in factories."),
- static const MessageKind MISSING_FACTORY_KEYWORD = const MessageKind(
- "Did you forget a factory keyword here?");
+ MessageKind.MISSING_FACTORY_KEYWORD:
+ const MessageTemplate(MessageKind.MISSING_FACTORY_KEYWORD,
+ "Did you forget a factory keyword here?"),
- static const MessageKind NO_SUCH_METHOD_IN_NATIVE =
- const MessageKind(
+ MessageKind.NO_SUCH_METHOD_IN_NATIVE:
+ const MessageTemplate(MessageKind.NO_SUCH_METHOD_IN_NATIVE,
"'NoSuchMethod' is not supported for classes that extend native "
- "classes.");
+ "classes."),
- static const MessageKind DEFERRED_LIBRARY_DART_2_DART =
- const MessageKind(
+ MessageKind.DEFERRED_LIBRARY_DART_2_DART:
+ const MessageTemplate(MessageKind.DEFERRED_LIBRARY_DART_2_DART,
"Deferred loading is not supported by the dart backend yet. "
- "The output will not be split.");
+ "The output will not be split."),
- static const MessageKind DEFERRED_LIBRARY_WITHOUT_PREFIX =
- const MessageKind(
+ MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX:
+ const MessageTemplate(MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX,
"This import is deferred but there is no prefix keyword.",
- howToFix:
- "Try adding a prefix to the import.");
+ howToFix: "Try adding a prefix to the import."),
- static const MessageKind DEFERRED_OLD_SYNTAX =
- const MessageKind(
+ MessageKind.DEFERRED_OLD_SYNTAX:
+ const MessageTemplate(MessageKind.DEFERRED_OLD_SYNTAX,
"The DeferredLibrary annotation is obsolete.",
howToFix:
- "Use the \"import 'lib.dart' deferred as prefix\" syntax instead.");
+ "Use the \"import 'lib.dart' deferred as prefix\" syntax instead."),
- static const MessageKind DEFERRED_LIBRARY_DUPLICATE_PREFIX =
- const MessageKind(
+ MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX:
+ const MessageTemplate(MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX,
"The prefix of this deferred import is not unique.",
- howToFix:
- "Try changing the import prefix.");
+ howToFix: "Try changing the import prefix."),
- static const MessageKind DEFERRED_TYPE_ANNOTATION =
- const MessageKind(
+ MessageKind.DEFERRED_TYPE_ANNOTATION:
+ const MessageTemplate(MessageKind.DEFERRED_TYPE_ANNOTATION,
"The type #{node} is deferred. "
"Deferred types are not valid as type annotations.",
howToFix:
- "Try using a non-deferred abstract class as an interface.");
+ "Try using a non-deferred abstract class as an interface."),
- static const MessageKind ILLEGAL_STATIC = const MessageKind(
- "Modifier static is only allowed on functions declared in "
- "a class.");
+ MessageKind.ILLEGAL_STATIC:
+ const MessageTemplate(MessageKind.ILLEGAL_STATIC,
+ "Modifier static is only allowed on functions declared in "
+ "a class."),
- static const MessageKind STATIC_FUNCTION_BLOAT = const MessageKind(
- "Using '#{class}.#{name}' may lead to unnecessarily large "
- "generated code.",
- howToFix:
- "Try adding '@MirrorsUsed(...)' as described at "
- "https://goo.gl/Akrrog.");
+ MessageKind.STATIC_FUNCTION_BLOAT:
+ const MessageTemplate(MessageKind.STATIC_FUNCTION_BLOAT,
+ "Using '#{class}.#{name}' may lead to unnecessarily large "
+ "generated code.",
+ howToFix:
+ "Try adding '@MirrorsUsed(...)' as described at "
+ "https://goo.gl/Akrrog."),
- static const MessageKind NON_CONST_BLOAT = const MessageKind(
- "Using 'new #{name}' may lead to unnecessarily large generated "
- "code.",
- howToFix:
- "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
- "described at https://goo.gl/Akrrog.");
+ MessageKind.NON_CONST_BLOAT:
+ const MessageTemplate(MessageKind.NON_CONST_BLOAT,
+ "Using 'new #{name}' may lead to unnecessarily large generated "
+ "code.",
+ howToFix:
+ "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
+ "described at https://goo.gl/Akrrog."),
- static const MessageKind STRING_EXPECTED = const MessageKind(
- "Expected a 'String', but got an instance of '#{type}'.");
+ MessageKind.STRING_EXPECTED:
+ const MessageTemplate(MessageKind.STRING_EXPECTED,
+ "Expected a 'String', but got an instance of '#{type}'."),
- static const MessageKind PRIVATE_IDENTIFIER = const MessageKind(
- "'#{value}' is not a valid Symbol name because it starts with "
- "'_'.");
+ MessageKind.PRIVATE_IDENTIFIER:
+ const MessageTemplate(MessageKind.PRIVATE_IDENTIFIER,
+ "'#{value}' is not a valid Symbol name because it starts with "
+ "'_'."),
- static const MessageKind PRIVATE_NAMED_PARAMETER = const MessageKind(
- "Named optional parameter can't have a library private name.",
- howToFix: "Try removing the '_' or making the parameter positional or "
- "required.",
- examples: const ["""foo({int _p}) {} main() => foo();"""]
- );
+ MessageKind.PRIVATE_NAMED_PARAMETER:
+ const MessageTemplate(MessageKind.PRIVATE_NAMED_PARAMETER,
+ "Named optional parameter can't have a library private name.",
+ howToFix:
+ "Try removing the '_' or making the parameter positional or "
+ "required.",
+ examples: const ["""foo({int _p}) {} main() => foo();"""]),
- static const MessageKind UNSUPPORTED_LITERAL_SYMBOL = const MessageKind(
- "Symbol literal '##{value}' is currently unsupported by dart2js.");
+ MessageKind.UNSUPPORTED_LITERAL_SYMBOL:
+ const MessageTemplate(MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
+ "Symbol literal '##{value}' is currently unsupported by dart2js."),
- static const MessageKind INVALID_SYMBOL = const MessageKind('''
+ MessageKind.INVALID_SYMBOL:
+ const MessageTemplate(MessageKind.INVALID_SYMBOL, '''
'#{value}' is not a valid Symbol name because is not:
* an empty String,
* a user defined operator,
* a qualified non-private identifier optionally followed by '=', or
* a qualified non-private identifier followed by '.' and a user-defined '''
-"operator.");
+"operator."),
- static const MessageKind AMBIGUOUS_REEXPORT = const MessageKind(
- "'#{name}' is (re)exported by multiple libraries.");
+ MessageKind.AMBIGUOUS_REEXPORT:
+ const MessageTemplate(MessageKind.AMBIGUOUS_REEXPORT,
+ "'#{name}' is (re)exported by multiple libraries."),
- static const MessageKind AMBIGUOUS_LOCATION = const MessageKind(
- "'#{name}' is defined here.");
+ MessageKind.AMBIGUOUS_LOCATION:
+ const MessageTemplate(MessageKind.AMBIGUOUS_LOCATION,
+ "'#{name}' is defined here."),
- static const MessageKind IMPORTED_HERE = const MessageKind(
- "'#{name}' is imported here.");
+ MessageKind.IMPORTED_HERE:
+ const MessageTemplate(MessageKind.IMPORTED_HERE,
+ "'#{name}' is imported here."),
- static const MessageKind OVERRIDE_EQUALS_NOT_HASH_CODE = const MessageKind(
- "The class '#{class}' overrides 'operator==', "
- "but not 'get hashCode'.");
+ MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE:
+ const MessageTemplate(MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
+ "The class '#{class}' overrides 'operator==', "
+ "but not 'get hashCode'."),
- static const MessageKind INTERNAL_LIBRARY_FROM = const MessageKind(
- "Internal library '#{resolvedUri}' is not accessible from "
- "'#{importingUri}'.");
+ MessageKind.INTERNAL_LIBRARY_FROM:
+ const MessageTemplate(MessageKind.INTERNAL_LIBRARY_FROM,
+ "Internal library '#{resolvedUri}' is not accessible from "
+ "'#{importingUri}'."),
- static const MessageKind INTERNAL_LIBRARY = const MessageKind(
- "Internal library '#{resolvedUri}' is not accessible.");
+ MessageKind.INTERNAL_LIBRARY:
+ const MessageTemplate(MessageKind.INTERNAL_LIBRARY,
+ "Internal library '#{resolvedUri}' is not accessible."),
- static const MessageKind LIBRARY_NOT_FOUND = const MessageKind(
- "Library not found '#{resolvedUri}'.");
+ MessageKind.LIBRARY_NOT_FOUND:
+ const MessageTemplate(MessageKind.LIBRARY_NOT_FOUND,
+ "Library not found '#{resolvedUri}'."),
- static const MessageKind UNSUPPORTED_EQ_EQ_EQ = const MessageKind(
- "'===' is not an operator. "
- "Did you mean '#{lhs} == #{rhs}' or 'identical(#{lhs}, #{rhs})'?");
+ MessageKind.UNSUPPORTED_EQ_EQ_EQ:
+ const MessageTemplate(MessageKind.UNSUPPORTED_EQ_EQ_EQ,
+ "'===' is not an operator. "
+ "Did you mean '#{lhs} == #{rhs}' or 'identical(#{lhs}, #{rhs})'?"),
- static const MessageKind UNSUPPORTED_BANG_EQ_EQ = const MessageKind(
- "'!==' is not an operator. "
- "Did you mean '#{lhs} != #{rhs}' or '!identical(#{lhs}, #{rhs})'?");
+ MessageKind.UNSUPPORTED_BANG_EQ_EQ:
+ const MessageTemplate(MessageKind.UNSUPPORTED_BANG_EQ_EQ,
+ "'!==' is not an operator. "
+ "Did you mean '#{lhs} != #{rhs}' or '!identical(#{lhs}, #{rhs})'?"),
- static const MessageKind UNSUPPORTED_PREFIX_PLUS = const MessageKind(
- "'+' is not a prefix operator. ",
- howToFix: "Try removing '+'.",
- examples: const [
- "main() => +2; // No longer a valid way to write '2'"
- ]);
+ MessageKind.UNSUPPORTED_PREFIX_PLUS:
+ const MessageTemplate(MessageKind.UNSUPPORTED_PREFIX_PLUS,
+ "'+' is not a prefix operator. ",
+ howToFix: "Try removing '+'.",
+ examples: const [
+ "main() => +2; // No longer a valid way to write '2'"
+ ]),
- static const MessageKind UNSUPPORTED_THROW_WITHOUT_EXP = const MessageKind(
- "No expression after 'throw'. "
- "Did you mean 'rethrow'?");
+ MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP:
+ const MessageTemplate(MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP,
+ "No expression after 'throw'. "
+ "Did you mean 'rethrow'?"),
- static const MessageKind DEPRECATED_TYPEDEF_MIXIN_SYNTAX = const MessageKind(
- "'typedef' not allowed here. ",
- howToFix: "Try replacing 'typedef' with 'class'.",
- examples: const [
- """
+ MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX:
+ const MessageTemplate(MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX,
+ "'typedef' not allowed here. ",
+ howToFix: "Try replacing 'typedef' with 'class'.",
+ examples: const [
+ """
class B { }
class M1 { }
typedef C = B with M1; // Need to replace 'typedef' with 'class'.
main() { new C(); }
-"""]
-);
+"""]),
- static const MessageKind MIRRORS_EXPECTED_STRING = const MessageKind(
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "and a 'String' value is expected.",
- howToFix: "Did you forget to add quotes?",
- examples: const [
- """
+ MessageKind.MIRRORS_EXPECTED_STRING:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "and a 'String' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
// 'Foo' is a type literal, not a string.
@MirrorsUsed(symbols: const [Foo])
import 'dart:mirrors';
@@ -1508,27 +2123,29 @@
class Foo {}
main() {}
-"""]);
+"""]),
- static const MessageKind MIRRORS_EXPECTED_STRING_OR_TYPE = const MessageKind(
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "and a 'String' or 'Type' value is expected.",
- howToFix: "Did you forget to add quotes?",
- examples: const [
- """
+ MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "and a 'String' or 'Type' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
// 'main' is a method, not a class.
@MirrorsUsed(targets: const [main])
import 'dart:mirrors';
main() {}
-"""]);
+"""]),
- static const MessageKind MIRRORS_EXPECTED_STRING_OR_LIST = const MessageKind(
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "and a 'String' or 'List' value is expected.",
- howToFix: "Did you forget to add quotes?",
- examples: const [
- """
+ MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "and a 'String' or 'List' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
// 'Foo' is not a string.
@MirrorsUsed(symbols: Foo)
import 'dart:mirrors';
@@ -1536,80 +2153,83 @@
class Foo {}
main() {}
-"""]);
+"""]),
- static const MessageKind MIRRORS_EXPECTED_STRING_TYPE_OR_LIST =
- const MessageKind(
- "Can't use '#{name}' here because it's an instance of '#{type}' "
- "but a 'String', 'Type', or 'List' value is expected.",
- howToFix: "Did you forget to add quotes?",
- examples: const [
- """
+ MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST:
+ const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST,
+ "Can't use '#{name}' here because it's an instance of '#{type}' "
+ "but a 'String', 'Type', or 'List' value is expected.",
+ howToFix: "Did you forget to add quotes?",
+ examples: const [
+ """
// '1' is not a string.
@MirrorsUsed(targets: 1)
import 'dart:mirrors';
main() {}
-"""]);
+"""]),
- static const MessageKind MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY =
- const MessageKind(
- "Can't find '#{name}' in the current library.",
- // TODO(ahe): The closest identifiers in edit distance would be nice.
- howToFix: "Did you forget to add an import?",
- examples: const [
- """
+ MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY:
+ const MessageTemplate(
+ MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
+ "Can't find '#{name}' in the current library.",
+ // TODO(ahe): The closest identifiers in edit distance would be nice.
+ howToFix: "Did you forget to add an import?",
+ examples: const [
+ """
// 'window' is not in scope because dart:html isn't imported.
@MirrorsUsed(targets: 'window')
import 'dart:mirrors';
main() {}
-"""]);
+"""]),
- static const MessageKind MIRRORS_CANNOT_RESOLVE_IN_LIBRARY =
- const MessageKind(
- "Can't find '#{name}' in the library '#{library}'.",
- // TODO(ahe): The closest identifiers in edit distance would be nice.
- howToFix: "Is '#{name}' spelled right?",
- examples: const [
- """
+ MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY:
+ const MessageTemplate(MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
+ "Can't find '#{name}' in the library '#{library}'.",
+ // TODO(ahe): The closest identifiers in edit distance would be nice.
+ howToFix: "Is '#{name}' spelled right?",
+ examples: const [
+ """
// 'List' is misspelled.
@MirrorsUsed(targets: 'dart.core.Lsit')
import 'dart:mirrors';
main() {}
-"""]);
+"""]),
- static const MessageKind MIRRORS_CANNOT_FIND_IN_ELEMENT =
- const MessageKind(
- "Can't find '#{name}' in '#{element}'.",
- // TODO(ahe): The closest identifiers in edit distance would be nice.
- howToFix: "Is '#{name}' spelled right?",
- examples: const [
- """
+ MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT:
+ const MessageTemplate(MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
+ "Can't find '#{name}' in '#{element}'.",
+ // TODO(ahe): The closest identifiers in edit distance would be nice.
+ howToFix: "Is '#{name}' spelled right?",
+ examples: const [
+ """
// 'addAll' is misspelled.
@MirrorsUsed(targets: 'dart.core.List.addAl')
import 'dart:mirrors';
main() {}
-"""]);
+"""]),
- static const MessageKind INVALID_URI = const MessageKind(
- "'#{uri}' is not a valid URI.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const [
- """
+ MessageKind.INVALID_URI:
+ const MessageTemplate(MessageKind.INVALID_URI,
+ "'#{uri}' is not a valid URI.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ """
// can't have a '[' in a URI
import '../../Udyn[mic ils/expect.dart';
main() {}
-"""]);
+"""]),
- static const MessageKind INVALID_PACKAGE_URI = const MessageKind(
- "'#{uri}' is not a valid package URI (#{exception}).",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const [
- """
+ MessageKind.INVALID_PACKAGE_URI:
+ const MessageTemplate(MessageKind.INVALID_PACKAGE_URI,
+ "'#{uri}' is not a valid package URI (#{exception}).",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ """
// can't have a 'top level' package URI
import 'package:foo.dart';
@@ -1624,156 +2244,175 @@
import 'package:not\valid/foo.dart';
main() {}
-"""]);
+"""]),
- static const MessageKind READ_SCRIPT_ERROR = const MessageKind(
- "Can't read '#{uri}' (#{exception}).",
- // Don't know how to fix since the underlying error is unknown.
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const [
- """
+ MessageKind.READ_SCRIPT_ERROR:
+ const MessageTemplate(MessageKind.READ_SCRIPT_ERROR,
+ "Can't read '#{uri}' (#{exception}).",
+ // Don't know how to fix since the underlying error is unknown.
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ """
// 'foo.dart' does not exist.
import 'foo.dart';
main() {}
-"""]);
+"""]),
- static const MessageKind READ_SELF_ERROR = const MessageKind(
- "#{exception}",
- // Don't know how to fix since the underlying error is unknown.
- howToFix: DONT_KNOW_HOW_TO_FIX);
+ MessageKind.READ_SELF_ERROR:
+ const MessageTemplate(MessageKind.READ_SELF_ERROR,
+ "#{exception}",
+ // Don't know how to fix since the underlying error is unknown.
+ howToFix: DONT_KNOW_HOW_TO_FIX),
- static const MessageKind EXTRANEOUS_MODIFIER = const MessageKind(
- "Can't have modifier '#{modifier}' here.",
- howToFix: "Try removing '#{modifier}'.",
- examples: const [
- "var String foo; main(){}",
- // "var get foo; main(){}",
- "var set foo; main(){}",
- "var final foo; main(){}",
- "var var foo; main(){}",
- "var const foo; main(){}",
- "var abstract foo; main(){}",
- "var static foo; main(){}",
- "var external foo; main(){}",
- "get var foo; main(){}",
- "set var foo; main(){}",
- "final var foo; main(){}",
- "var var foo; main(){}",
- "const var foo; main(){}",
- "abstract var foo; main(){}",
- "static var foo; main(){}",
- "external var foo; main(){}"]);
+ MessageKind.EXTRANEOUS_MODIFIER:
+ const MessageTemplate(MessageKind.EXTRANEOUS_MODIFIER,
+ "Can't have modifier '#{modifier}' here.",
+ howToFix: "Try removing '#{modifier}'.",
+ examples: const [
+ "var String foo; main(){}",
+ // "var get foo; main(){}",
+ "var set foo; main(){}",
+ "var final foo; main(){}",
+ "var var foo; main(){}",
+ "var const foo; main(){}",
+ "var abstract foo; main(){}",
+ "var static foo; main(){}",
+ "var external foo; main(){}",
+ "get var foo; main(){}",
+ "set var foo; main(){}",
+ "final var foo; main(){}",
+ "var var foo; main(){}",
+ "const var foo; main(){}",
+ "abstract var foo; main(){}",
+ "static var foo; main(){}",
+ "external var foo; main(){}"]),
- static const MessageKind EXTRANEOUS_MODIFIER_REPLACE = const MessageKind(
- "Can't have modifier '#{modifier}' here.",
- howToFix: "Try replacing modifier '#{modifier}' with 'var', 'final',"
- " or a type.",
- examples: const [
- // "get foo; main(){}",
- "set foo; main(){}",
- "abstract foo; main(){}",
- "static foo; main(){}",
- "external foo; main(){}"]);
+ MessageKind.EXTRANEOUS_MODIFIER_REPLACE:
+ const MessageTemplate(MessageKind.EXTRANEOUS_MODIFIER_REPLACE,
+ "Can't have modifier '#{modifier}' here.",
+ howToFix:
+ "Try replacing modifier '#{modifier}' with 'var', 'final', "
+ "or a type.",
+ examples: const [
+ // "get foo; main(){}",
+ "set foo; main(){}",
+ "abstract foo; main(){}",
+ "static foo; main(){}",
+ "external foo; main(){}"]),
- static const MessageKind ABSTRACT_CLASS_INSTANTIATION = const MessageKind(
- "Can't instantiate abstract class.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const ["abstract class A {} main() { new A(); }"]);
+ MessageKind.ABSTRACT_CLASS_INSTANTIATION:
+ const MessageTemplate(MessageKind.ABSTRACT_CLASS_INSTANTIATION,
+ "Can't instantiate abstract class.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["abstract class A {} main() { new A(); }"]),
- static const MessageKind BODY_EXPECTED = const MessageKind(
- "Expected a function body or '=>'.",
- // TODO(ahe): In some scenarios, we can suggest removing the 'static'
- // keyword.
- howToFix: "Try adding {}.",
- examples: const [
- "main();"]);
+ MessageKind.BODY_EXPECTED:
+ const MessageTemplate(MessageKind.BODY_EXPECTED,
+ "Expected a function body or '=>'.",
+ // TODO(ahe): In some scenarios, we can suggest removing the 'static'
+ // keyword.
+ howToFix: "Try adding {}.",
+ examples: const [
+ "main();"]),
- static const MessageKind MIRROR_BLOAT = const MessageKind(
- "#{count} methods retained for use by dart:mirrors out of #{total}"
- " total methods (#{percentage}%).");
+ MessageKind.MIRROR_BLOAT:
+ const MessageTemplate(MessageKind.MIRROR_BLOAT,
+ "#{count} methods retained for use by dart:mirrors out of #{total}"
+ " total methods (#{percentage}%)."),
- static const MessageKind MIRROR_IMPORT = const MessageKind(
- "Import of 'dart:mirrors'.");
+ MessageKind.MIRROR_IMPORT:
+ const MessageTemplate(MessageKind.MIRROR_IMPORT,
+ "Import of 'dart:mirrors'."),
- static const MessageKind MIRROR_IMPORT_NO_USAGE = const MessageKind(
- "This import is not annotated with @MirrorsUsed, which may lead to "
- "unnecessarily large generated code.",
- howToFix:
- "Try adding '@MirrorsUsed(...)' as described at "
- "https://goo.gl/Akrrog.");
+ MessageKind.MIRROR_IMPORT_NO_USAGE:
+ const MessageTemplate(MessageKind.MIRROR_IMPORT_NO_USAGE,
+ "This import is not annotated with @MirrorsUsed, which may lead to "
+ "unnecessarily large generated code.",
+ howToFix:
+ "Try adding '@MirrorsUsed(...)' as described at "
+ "https://goo.gl/Akrrog."),
- static const MessageKind WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT =
- const MessageKind(
- "Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant.");
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT:
+ const MessageTemplate(
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT,
+ "Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant."),
- static const MessageKind EXPECTED_IDENTIFIER_NOT_RESERVED_WORD =
- const MessageKind(
- "'#{keyword}' is a reserved word and can't be used here.",
- howToFix: "Try using a different name.",
- examples: const ["do() {} main() {}"]);
+ MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD:
+ const MessageTemplate(MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+ "'#{keyword}' is a reserved word and can't be used here.",
+ howToFix: "Try using a different name.",
+ examples: const ["do() {} main() {}"]),
- static const MessageKind NAMED_FUNCTION_EXPRESSION =
- const MessageKind("Function expression '#{name}' cannot be named.",
+ MessageKind. NAMED_FUNCTION_EXPRESSION:
+ const MessageTemplate(MessageKind.NAMED_FUNCTION_EXPRESSION,
+ "Function expression '#{name}' cannot be named.",
howToFix: "Try removing the name.",
- examples: const ["main() { var f = func() {}; }"]);
+ examples: const ["main() { var f = func() {}; }"]),
- static const MessageKind UNUSED_METHOD = const MessageKind(
- "The method '#{name}' is never called.",
- howToFix: "Consider deleting it.",
- examples: const ["deadCode() {} main() {}"]);
+ MessageKind.UNUSED_METHOD:
+ const MessageTemplate(MessageKind.UNUSED_METHOD,
+ "The method '#{name}' is never called.",
+ howToFix: "Consider deleting it.",
+ examples: const ["deadCode() {} main() {}"]),
- static const MessageKind UNUSED_CLASS = const MessageKind(
- "The class '#{name}' is never used.",
- howToFix: "Consider deleting it.",
- examples: const ["class DeadCode {} main() {}"]);
+ MessageKind.UNUSED_CLASS:
+ const MessageTemplate(MessageKind.UNUSED_CLASS,
+ "The class '#{name}' is never used.",
+ howToFix: "Consider deleting it.",
+ examples: const ["class DeadCode {} main() {}"]),
- static const MessageKind UNUSED_TYPEDEF = const MessageKind(
- "The typedef '#{name}' is never used.",
- howToFix: "Consider deleting it.",
- examples: const ["typedef DeadCode(); main() {}"]);
+ MessageKind.UNUSED_TYPEDEF:
+ const MessageTemplate(MessageKind.UNUSED_TYPEDEF,
+ "The typedef '#{name}' is never used.",
+ howToFix: "Consider deleting it.",
+ examples: const ["typedef DeadCode(); main() {}"]),
- static const MessageKind ABSTRACT_METHOD = const MessageKind(
- "The method '#{name}' has no implementation in "
- "class '#{class}'.",
- howToFix: "Try adding a body to '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.ABSTRACT_METHOD:
+ const MessageTemplate(MessageKind.ABSTRACT_METHOD,
+ "The method '#{name}' has no implementation in "
+ "class '#{class}'.",
+ howToFix: "Try adding a body to '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
class Class {
method();
}
main() => new Class().method();
-"""]);
+"""]),
- static const MessageKind ABSTRACT_GETTER = const MessageKind(
- "The getter '#{name}' has no implementation in "
- "class '#{class}'.",
- howToFix: "Try adding a body to '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.ABSTRACT_GETTER:
+ const MessageTemplate(MessageKind.ABSTRACT_GETTER,
+ "The getter '#{name}' has no implementation in "
+ "class '#{class}'.",
+ howToFix: "Try adding a body to '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
class Class {
get getter;
}
main() => new Class();
-"""]);
+"""]),
- static const MessageKind ABSTRACT_SETTER = const MessageKind(
- "The setter '#{name}' has no implementation in "
- "class '#{class}'.",
- howToFix: "Try adding a body to '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.ABSTRACT_SETTER:
+ const MessageTemplate(MessageKind.ABSTRACT_SETTER,
+ "The setter '#{name}' has no implementation in "
+ "class '#{class}'.",
+ howToFix: "Try adding a body to '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
class Class {
set setter(_);
}
main() => new Class();
-"""]);
+"""]),
- static const MessageKind INHERIT_GETTER_AND_METHOD = const MessageKind(
- "The class '#{class}' can't inherit both getters and methods "
- "by the named '#{name}'.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const ["""
+ MessageKind.INHERIT_GETTER_AND_METHOD:
+ const MessageTemplate(MessageKind.INHERIT_GETTER_AND_METHOD,
+ "The class '#{class}' can't inherit both getters and methods "
+ "by the named '#{name}'.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["""
class A {
get member => null;
}
@@ -1783,26 +2422,30 @@
class Class implements A, B {
}
main() => new Class();
-"""]);
+"""]),
- static const MessageKind INHERITED_METHOD = const MessageKind(
- "The inherited method '#{name}' is declared here in class "
- "'#{class}'.");
+ MessageKind.INHERITED_METHOD:
+ const MessageTemplate(MessageKind.INHERITED_METHOD,
+ "The inherited method '#{name}' is declared here in class "
+ "'#{class}'."),
- static const MessageKind INHERITED_EXPLICIT_GETTER = const MessageKind(
- "The inherited getter '#{name}' is declared here in class "
- "'#{class}'.");
+ MessageKind.INHERITED_EXPLICIT_GETTER:
+ const MessageTemplate(MessageKind.INHERITED_EXPLICIT_GETTER,
+ "The inherited getter '#{name}' is declared here in class "
+ "'#{class}'."),
- static const MessageKind INHERITED_IMPLICIT_GETTER = const MessageKind(
- "The inherited getter '#{name}' is implicitly declared by this "
- "field in class '#{class}'.");
+ MessageKind.INHERITED_IMPLICIT_GETTER:
+ const MessageTemplate(MessageKind.INHERITED_IMPLICIT_GETTER,
+ "The inherited getter '#{name}' is implicitly declared by this "
+ "field in class '#{class}'."),
- static const MessageKind UNIMPLEMENTED_METHOD_ONE = const MessageKind(
- "'#{class}' doesn't implement '#{method}' "
- "declared in '#{declarer}'.",
- howToFix: "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.UNIMPLEMENTED_METHOD_ONE:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD_ONE,
+ "'#{class}' doesn't implement '#{method}' "
+ "declared in '#{declarer}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
abstract class I {
m();
}
@@ -1814,13 +2457,14 @@
}
class C extends I {}
main() => new C();
-"""]);
+"""]),
- static const MessageKind UNIMPLEMENTED_METHOD = const MessageKind(
- "'#{class}' doesn't implement '#{method}'.",
- howToFix: "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.UNIMPLEMENTED_METHOD:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD,
+ "'#{class}' doesn't implement '#{method}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
abstract class I {
m();
}
@@ -1848,17 +2492,19 @@
main() {
new C();
}
-"""]);
+"""]),
- static const MessageKind UNIMPLEMENTED_METHOD_CONT = const MessageKind(
- "The method '#{name}' is declared here in class '#{class}'.");
+ MessageKind.UNIMPLEMENTED_METHOD_CONT:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD_CONT,
+ "The method '#{name}' is declared here in class '#{class}'."),
- static const MessageKind UNIMPLEMENTED_SETTER_ONE = const MessageKind(
- "'#{class}' doesn't implement the setter '#{name}' "
- "declared in '#{declarer}'.",
- howToFix: "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.UNIMPLEMENTED_SETTER_ONE:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_SETTER_ONE,
+ "'#{class}' doesn't implement the setter '#{name}' "
+ "declared in '#{declarer}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
abstract class I {
set m(_);
}
@@ -1870,13 +2516,14 @@
new D().m = 0;
new C();
}
-"""]);
+"""]),
- static const MessageKind UNIMPLEMENTED_SETTER = const MessageKind(
- "'#{class}' doesn't implement the setter '#{name}'.",
- howToFix: "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.UNIMPLEMENTED_SETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_SETTER,
+ "'#{class}' doesn't implement the setter '#{name}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
abstract class I {
set m(_);
}
@@ -1894,21 +2541,24 @@
}
class C extends I implements J {}
main() => new C();
-"""]);
+"""]),
- static const MessageKind UNIMPLEMENTED_EXPLICIT_SETTER = const MessageKind(
- "The setter '#{name}' is declared here in class '#{class}'.");
+ MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER,
+ "The setter '#{name}' is declared here in class '#{class}'."),
- static const MessageKind UNIMPLEMENTED_IMPLICIT_SETTER = const MessageKind(
- "The setter '#{name}' is implicitly declared by this field "
- "in class '#{class}'.");
+ MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER,
+ "The setter '#{name}' is implicitly declared by this field "
+ "in class '#{class}'."),
- static const MessageKind UNIMPLEMENTED_GETTER_ONE = const MessageKind(
- "'#{class}' doesn't implement the getter '#{name}' "
- "declared in '#{declarer}'.",
- howToFix: "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.UNIMPLEMENTED_GETTER_ONE:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_GETTER_ONE,
+ "'#{class}' doesn't implement the getter '#{name}' "
+ "declared in '#{declarer}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
abstract class I {
get m;
}
@@ -1920,13 +2570,14 @@
}
class C extends I {}
main() => new C();
-"""]);
+"""]),
- static const MessageKind UNIMPLEMENTED_GETTER = const MessageKind(
- "'#{class}' doesn't implement the getter '#{name}'.",
- howToFix: "Try adding an implementation of '#{name}' or declaring "
- "'#{class}' to be 'abstract'.",
- examples: const ["""
+ MessageKind.UNIMPLEMENTED_GETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_GETTER,
+ "'#{class}' doesn't implement the getter '#{name}'.",
+ howToFix: "Try adding an implementation of '#{name}' or declaring "
+ "'#{class}' to be 'abstract'.",
+ examples: const ["""
abstract class I {
get m;
}
@@ -1944,37 +2595,43 @@
}
class C extends I implements J {}
main() => new C();
-"""]);
+"""]),
- static const MessageKind UNIMPLEMENTED_EXPLICIT_GETTER = const MessageKind(
- "The getter '#{name}' is declared here in class '#{class}'.");
+ MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER,
+ "The getter '#{name}' is declared here in class '#{class}'."),
- static const MessageKind UNIMPLEMENTED_IMPLICIT_GETTER = const MessageKind(
- "The getter '#{name}' is implicitly declared by this field "
- "in class '#{class}'.");
+ MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER:
+ const MessageTemplate(MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER,
+ "The getter '#{name}' is implicitly declared by this field "
+ "in class '#{class}'."),
- static const MessageKind EQUAL_MAP_ENTRY_KEY = const MessageKind(
- "An entry with the same key already exists in the map.",
- howToFix: "Try removing the previous entry or changing the key in one "
- "of the entries.",
- examples: const ["""
+ MessageKind.EQUAL_MAP_ENTRY_KEY:
+ const MessageTemplate(MessageKind.EQUAL_MAP_ENTRY_KEY,
+ "An entry with the same key already exists in the map.",
+ howToFix:
+ "Try removing the previous entry or changing the key in one "
+ "of the entries.",
+ examples: const ["""
main() {
var m = const {'foo': 1, 'foo': 2};
-}"""]);
+}"""]),
- static const MessageKind BAD_INPUT_CHARACTER = const MessageKind(
- "Character U+#{characterHex} isn't allowed here.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const ["""
+ MessageKind.BAD_INPUT_CHARACTER:
+ const MessageTemplate(MessageKind.BAD_INPUT_CHARACTER,
+ "Character U+#{characterHex} isn't allowed here.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["""
main() {
String x = ç;
}
-"""]);
+"""]),
- static const MessageKind UNTERMINATED_STRING = const MessageKind(
- "String must end with #{quote}.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const ["""
+ MessageKind.UNTERMINATED_STRING:
+ const MessageTemplate(MessageKind.UNTERMINATED_STRING,
+ "String must end with #{quote}.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const ["""
main() {
return '
;
@@ -2009,46 +2666,53 @@
""",
"""
main() => r\"\"\"
-"""]);
+"""]),
- static const MessageKind UNMATCHED_TOKEN = const MessageKind(
- "Can't find '#{end}' to match '#{begin}'.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const[
- "main(",
- "main(){",
- "main(){]}",
- ]);
+ MessageKind.UNMATCHED_TOKEN:
+ const MessageTemplate(MessageKind.UNMATCHED_TOKEN,
+ "Can't find '#{end}' to match '#{begin}'.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const[
+ "main(",
+ "main(){",
+ "main(){]}",
+ ]),
- static const MessageKind UNTERMINATED_TOKEN = const MessageKind(
- // This is a fall-back message that shouldn't happen.
- "Incomplete token.");
+ MessageKind.UNTERMINATED_TOKEN:
+ const MessageTemplate(MessageKind.UNTERMINATED_TOKEN,
+ // This is a fall-back message that shouldn't happen.
+ "Incomplete token."),
- static const MessageKind EXPONENT_MISSING = const MessageKind(
- "Numbers in exponential notation should always contain an exponent"
- " (an integer number with an optional sign).",
- howToFix: "Make sure there is an exponent, and remove any whitespace "
- "before it.",
- examples: const ["""
+ MessageKind.EXPONENT_MISSING:
+ const MessageTemplate(MessageKind.EXPONENT_MISSING,
+ "Numbers in exponential notation should always contain an exponent"
+ " (an integer number with an optional sign).",
+ howToFix:
+ "Make sure there is an exponent, and remove any whitespace "
+ "before it.",
+ examples: const ["""
main() {
var i = 1e;
}
-"""]);
+"""]),
- static const MessageKind HEX_DIGIT_EXPECTED = const MessageKind(
- "A hex digit (0-9 or A-F) must follow '0x'.",
- howToFix: DONT_KNOW_HOW_TO_FIX, // Seems obvious from the error message.
- examples: const ["""
+ MessageKind.HEX_DIGIT_EXPECTED:
+ const MessageTemplate(MessageKind.HEX_DIGIT_EXPECTED,
+ "A hex digit (0-9 or A-F) must follow '0x'.",
+ howToFix:
+ DONT_KNOW_HOW_TO_FIX, // Seems obvious from the error message.
+ examples: const ["""
main() {
var i = 0x;
}
-"""]);
+"""]),
- static const MessageKind MALFORMED_STRING_LITERAL = const MessageKind(
- r"A '$' has special meaning inside a string, and must be followed by an"
- " identifier or an expression in curly braces ({}).",
- howToFix: r"Try adding a backslash (\) to escape the '$'.",
- examples: const [r"""
+ MessageKind.MALFORMED_STRING_LITERAL:
+ const MessageTemplate(MessageKind.MALFORMED_STRING_LITERAL,
+ r"A '$' has special meaning inside a string, and must be followed by "
+ "an identifier or an expression in curly braces ({}).",
+ howToFix: r"Try adding a backslash (\) to escape the '$'.",
+ examples: const [r"""
main() {
return '$';
}
@@ -2067,34 +2731,37 @@
main() {
return """$""";
}
-''']);
+''']),
- static const MessageKind UNTERMINATED_COMMENT = const MessageKind(
- "Comment starting with '/*' must end with '*/'.",
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const [r"""
+ MessageKind.UNTERMINATED_COMMENT:
+ const MessageTemplate(MessageKind.UNTERMINATED_COMMENT,
+ "Comment starting with '/*' must end with '*/'.",
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [r"""
main() {
}
-/*"""]);
+/*"""]),
- static const MessageKind MISSING_TOKEN_BEFORE_THIS = const MessageKind(
- "Expected '#{token}' before this.",
- // Consider the second example below: the parser expects a ')' before
- // 'y', but a ',' would also have worked. We don't have enough
- // information to give a good suggestion.
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const [
- "main() => true ? 1;",
- "main() => foo(x: 1 y: 2);",
- ]);
+ MessageKind.MISSING_TOKEN_BEFORE_THIS:
+ const MessageTemplate(MessageKind.MISSING_TOKEN_BEFORE_THIS,
+ "Expected '#{token}' before this.",
+ // Consider the second example below: the parser expects a ')' before
+ // 'y', but a ',' would also have worked. We don't have enough
+ // information to give a good suggestion.
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ "main() => true ? 1;",
+ "main() => foo(x: 1 y: 2);",
+ ]),
- static const MessageKind MISSING_TOKEN_AFTER_THIS = const MessageKind(
- "Expected '#{token}' after this.",
- // See [MISSING_TOKEN_BEFORE_THIS], we don't have enough information to
- // give a good suggestion.
- howToFix: DONT_KNOW_HOW_TO_FIX,
- examples: const [
- "main(x) {x}",
+ MessageKind.MISSING_TOKEN_AFTER_THIS:
+ const MessageTemplate(MessageKind.MISSING_TOKEN_AFTER_THIS,
+ "Expected '#{token}' after this.",
+ // See [MISSING_TOKEN_BEFORE_THIS], we don't have enough information
+ // to give a good suggestion.
+ howToFix: DONT_KNOW_HOW_TO_FIX,
+ examples: const [
+ "main(x) {x}",
"""
class S1 {}
class S2 {}
@@ -2102,34 +2769,40 @@
class A = S1 with S2, S3
main() => new A();
"""
-]);
+]),
- static const MessageKind CONSIDER_ANALYZE_ALL = const MessageKind(
- "Could not find '#{main}'. Nothing will be analyzed.",
- howToFix: "Try using '--analyze-all' to analyze everything.",
- examples: const ['']);
+ MessageKind.CONSIDER_ANALYZE_ALL:
+ const MessageTemplate(MessageKind.CONSIDER_ANALYZE_ALL,
+ "Could not find '#{main}'. Nothing will be analyzed.",
+ howToFix: "Try using '--analyze-all' to analyze everything.",
+ examples: const ['']),
- static const MessageKind MISSING_MAIN = const MessageKind(
- "Could not find '#{main}'.",
- howToFix: "Try adding a method named '#{main}' to your program."
- /* No example, test uses '--analyze-only' which will produce the above
- * message [CONSIDER_ANALYZE_ALL]. An example for a human operator would
- * be an empty file. */);
+ MessageKind.MISSING_MAIN:
+ const MessageTemplate(MessageKind.MISSING_MAIN,
+ "Could not find '#{main}'.",
+ howToFix: "Try adding a method named '#{main}' to your program."
+ /* No example, test uses '--analyze-only' which will produce the above
+ * message [CONSIDER_ANALYZE_ALL]. An example for a human operator
+ * would be an empty file.*/),
- static const MessageKind MAIN_NOT_A_FUNCTION = const MessageKind(
- "'#{main}' is not a function.",
- howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
- examples: const ['var main;']);
+ MessageKind.MAIN_NOT_A_FUNCTION:
+ const MessageTemplate(MessageKind.MAIN_NOT_A_FUNCTION,
+ "'#{main}' is not a function.",
+ howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+ examples: const ['var main;']),
- static const MessageKind MAIN_WITH_EXTRA_PARAMETER = const MessageKind(
- "'#{main}' cannot have more than two parameters.",
- howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
- examples: const ['main(a, b, c) {}']);
+ MessageKind.MAIN_WITH_EXTRA_PARAMETER:
+ const MessageTemplate(MessageKind.MAIN_WITH_EXTRA_PARAMETER,
+ "'#{main}' cannot have more than two parameters.",
+ howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+ examples: const ['main(a, b, c) {}']),
- static const MessageKind COMPILER_CRASHED = const MessageKind(
- "The compiler crashed when compiling this element.");
+ MessageKind.COMPILER_CRASHED:
+ const MessageTemplate(MessageKind.COMPILER_CRASHED,
+ "The compiler crashed when compiling this element."),
- static const MessageKind PLEASE_REPORT_THE_CRASH = const MessageKind('''
+ MessageKind.PLEASE_REPORT_THE_CRASH:
+ const MessageTemplate(MessageKind.PLEASE_REPORT_THE_CRASH, '''
The compiler is broken.
When compiling the above element, the compiler crashed. It is not
@@ -2147,84 +2820,100 @@
* the entire message you see here (including the full stack trace
below as well as the source location above).
-''');
+'''),
- static const MessageKind POTENTIAL_MUTATION = const MessageKind(
- "Variable '#{variableName}' is not known to be of type "
- "'#{shownType}' because it is potentially mutated in the scope for "
- "promotion.");
+ MessageKind.POTENTIAL_MUTATION:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION,
+ "Variable '#{variableName}' is not known to be of type "
+ "'#{shownType}' because it is potentially mutated in the scope for "
+ "promotion."),
- static const MessageKind POTENTIAL_MUTATION_HERE = const MessageKind(
- "Variable '#{variableName}' is potentially mutated here.");
+ MessageKind.POTENTIAL_MUTATION_HERE:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION_HERE,
+ "Variable '#{variableName}' is potentially mutated here."),
- static const MessageKind POTENTIAL_MUTATION_IN_CLOSURE = const MessageKind(
- "Variable '#{variableName}' is not known to be of type "
- "'#{shownType}' because it is potentially mutated within a closure.");
+ MessageKind.POTENTIAL_MUTATION_IN_CLOSURE:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION_IN_CLOSURE,
+ "Variable '#{variableName}' is not known to be of type "
+ "'#{shownType}' because it is potentially mutated within a closure."),
- static const MessageKind POTENTIAL_MUTATION_IN_CLOSURE_HERE =
- const MessageKind(
- "Variable '#{variableName}' is potentially mutated in a "
- "closure here.");
+ MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE:
+ const MessageTemplate(MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE,
+ "Variable '#{variableName}' is potentially mutated in a "
+ "closure here."),
- static const MessageKind ACCESSED_IN_CLOSURE = const MessageKind(
- "Variable '#{variableName}' is not known to be of type "
- "'#{shownType}' because it is accessed by a closure in the scope for "
- "promotion and potentially mutated in the scope of '#{variableName}'.");
+ MessageKind.ACCESSED_IN_CLOSURE:
+ const MessageTemplate(MessageKind.ACCESSED_IN_CLOSURE,
+ "Variable '#{variableName}' is not known to be of type "
+ "'#{shownType}' because it is accessed by a closure in the scope for "
+ "promotion and potentially mutated in the scope of "
+ "'#{variableName}'."),
- static const MessageKind ACCESSED_IN_CLOSURE_HERE = const MessageKind(
- "Variable '#{variableName}' is accessed in a closure here.");
+ MessageKind.ACCESSED_IN_CLOSURE_HERE:
+ const MessageTemplate(MessageKind.ACCESSED_IN_CLOSURE_HERE,
+ "Variable '#{variableName}' is accessed in a closure here."),
- static const MessageKind NOT_MORE_SPECIFIC = const MessageKind(
- "Variable '#{variableName}' is not shown to have type "
- "'#{shownType}' because '#{shownType}' is not more specific than the "
- "known type '#{knownType}' of '#{variableName}'.");
+ MessageKind.NOT_MORE_SPECIFIC:
+ const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC,
+ "Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not more specific than the "
+ "known type '#{knownType}' of '#{variableName}'."),
- static const MessageKind NOT_MORE_SPECIFIC_SUBTYPE = const MessageKind(
- "Variable '#{variableName}' is not shown to have type "
- "'#{shownType}' because '#{shownType}' is not a subtype of the "
- "known type '#{knownType}' of '#{variableName}'.");
+ MessageKind.NOT_MORE_SPECIFIC_SUBTYPE:
+ const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
+ "Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not a subtype of the "
+ "known type '#{knownType}' of '#{variableName}'."),
- static const MessageKind NOT_MORE_SPECIFIC_SUGGESTION = const MessageKind(
- "Variable '#{variableName}' is not shown to have type "
- "'#{shownType}' because '#{shownType}' is not more specific than the "
- "known type '#{knownType}' of '#{variableName}'.",
- howToFix: "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'.");
+ MessageKind.NOT_MORE_SPECIFIC_SUGGESTION:
+ const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+ "Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not more specific than the "
+ "known type '#{knownType}' of '#{variableName}'.",
+ howToFix:
+ "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'."),
- static const MessageKind HIDDEN_WARNINGS_HINTS = const MessageKind(
- "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}.");
+ MessageKind.HIDDEN_WARNINGS_HINTS:
+ const MessageTemplate(MessageKind.HIDDEN_WARNINGS_HINTS,
+ "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}."),
- static const MessageKind HIDDEN_WARNINGS = const MessageKind(
- "#{warnings} warning(s) suppressed in #{uri}.");
+ MessageKind.HIDDEN_WARNINGS:
+ const MessageTemplate(MessageKind.HIDDEN_WARNINGS,
+ "#{warnings} warning(s) suppressed in #{uri}."),
- static const MessageKind HIDDEN_HINTS = const MessageKind(
- "#{hints} hint(s) suppressed in #{uri}.");
+ MessageKind.HIDDEN_HINTS:
+ const MessageTemplate(MessageKind.HIDDEN_HINTS,
+ "#{hints} hint(s) suppressed in #{uri}."),
- static const MessageKind PREAMBLE = const MessageKind(
- "When run on the command-line, the compiled output might"
- " require a preamble file located in:\n"
- " <sdk>/lib/_internal/js_runtime/lib/preambles.");
+ MessageKind.PREAMBLE:
+ const MessageTemplate(MessageKind.PREAMBLE,
+ "When run on the command-line, the compiled output might"
+ " require a preamble file located in:\n"
+ " <sdk>/lib/_internal/js_runtime/lib/preambles."),
- static const MessageKind INVALID_SYNC_MODIFIER = const MessageKind(
- "Invalid modifier 'sync'.",
- options: const ['--enable-async'],
- howToFix: "Try replacing 'sync' with 'sync*'.",
- examples: const [
- "main() sync {}"
- ]);
+ MessageKind.INVALID_SYNC_MODIFIER:
+ const MessageTemplate(MessageKind.INVALID_SYNC_MODIFIER,
+ "Invalid modifier 'sync'.",
+ options: const ['--enable-async'],
+ howToFix: "Try replacing 'sync' with 'sync*'.",
+ examples: const [
+ "main() sync {}"
+ ]),
- static const MessageKind INVALID_AWAIT_FOR = const MessageKind(
- "'await' is only supported on for-in loops.",
- options: const ['--enable-async'],
- howToFix: "Try rewriting the loop as a for-in loop or removing the "
- "'await' keyword.",
- examples: const ["""
+ MessageKind.INVALID_AWAIT_FOR:
+ const MessageTemplate(MessageKind.INVALID_AWAIT_FOR,
+ "'await' is only supported on for-in loops.",
+ options: const ['--enable-async'],
+ howToFix: "Try rewriting the loop as a for-in loop or removing the "
+ "'await' keyword.",
+ examples: const ["""
main() async* {
await for (int i = 0; i < 10; i++) {}
}
-"""]);
+"""]),
- static const MessageKind ASYNC_MODIFIER_ON_ABSTRACT_METHOD =
- const MessageKind(
+ MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD:
+ const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
"The modifier '#{modifier}' is not allowed on an abstract method.",
options: const ['--enable-async'],
howToFix: "Try removing the '#{modifier}' modifier or adding a "
@@ -2240,14 +2929,14 @@
A a = new B();
a.method();
}
-"""]);
+"""]),
- static const MessageKind ASYNC_MODIFIER_ON_CONSTRUCTOR =
- const MessageKind(
- "The modifier '#{modifier}' is not allowed on constructors.",
- options: const ['--enable-async'],
- howToFix: "Try removing the '#{modifier}' modifier.",
- examples: const ["""
+ MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR,
+ "The modifier '#{modifier}' is not allowed on constructors.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier.",
+ examples: const ["""
class A {
A() async;
}
@@ -2258,36 +2947,37 @@
A();
factory A.a() async* {}
}
-main() => new A.a();"""]);
+main() => new A.a();"""]),
- static const MessageKind ASYNC_MODIFIER_ON_SETTER =
- const MessageKind(
- "The modifier '#{modifier}' is not allowed on setters.",
- options: const ['--enable-async'],
- howToFix: "Try removing the '#{modifier}' modifier.",
- examples: const ["""
+ MessageKind.ASYNC_MODIFIER_ON_SETTER:
+ const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_SETTER,
+ "The modifier '#{modifier}' is not allowed on setters.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier.",
+ examples: const ["""
class A {
set foo(v) async {}
}
-main() => new A().foo = 0;"""]);
+main() => new A().foo = 0;"""]),
- static const MessageKind YIELDING_MODIFIER_ON_ARROW_BODY =
- const MessageKind(
+ MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY:
+ const MessageTemplate(MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
"The modifier '#{modifier}' is not allowed on methods implemented "
"using '=>'.",
options: const ['--enable-async'],
howToFix: "Try removing the '#{modifier}' modifier or implementing "
"the method body using a block: '{ ... }'.",
- examples: const ["main() sync* => null;", "main() async* => null;"]);
+ examples: const ["main() sync* => null;", "main() async* => null;"]),
- // TODO(johnniwinther): Check for 'async' as identifier.
- static const MessageKind ASYNC_KEYWORD_AS_IDENTIFIER = const MessageKind(
- "'#{keyword}' cannot be used as an identifier in a function body marked "
- "with '#{modifier}'.",
- options: const ['--enable-async'],
- howToFix: "Try removing the '#{modifier}' modifier or renaming the "
- "identifier.",
- examples: const ["""
+ // TODO(johnniwinther): Check for 'async' as identifier.
+ MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER:
+ const MessageTemplate(MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER,
+ "'#{keyword}' cannot be used as an identifier in a function body "
+ "marked with '#{modifier}'.",
+ options: const ['--enable-async'],
+ howToFix: "Try removing the '#{modifier}' modifier or renaming the "
+ "identifier.",
+ examples: const ["""
main() async {
var await;
}""",
@@ -2298,10 +2988,10 @@
"""
main() sync* {
var yield;
-}"""]);
+}"""]),
- static const MessageKind RETURN_IN_GENERATOR =
- const MessageKind(
+ MessageKind.RETURN_IN_GENERATOR:
+ const MessageTemplate(MessageKind.RETURN_IN_GENERATOR,
"'return' with a value is not allowed in a method body using the "
"'#{modifier}' modifier.",
howToFix: "Try removing the value, replacing 'return' with 'yield' "
@@ -2315,41 +3005,45 @@
"""
foo() sync* { return 0; }
main() => foo();
-"""]);
+"""]),
- static const MessageKind NATIVE_NOT_SUPPORTED = const MessageKind(
- "'native' modifier is not supported.",
- howToFix: "Try removing the 'native' implementation or analyzing the "
- "code with the --allow-native-extensions option.",
- examples: const ["""
+ MessageKind.NATIVE_NOT_SUPPORTED:
+ const MessageTemplate(MessageKind.NATIVE_NOT_SUPPORTED,
+ "'native' modifier is not supported.",
+ howToFix: "Try removing the 'native' implementation or analyzing the "
+ "code with the --allow-native-extensions option.",
+ examples: const ["""
main() native "Main";
-"""]);
+"""]),
- static const MessageKind DART_EXT_NOT_SUPPORTED = const MessageKind(
- "The 'dart-ext' scheme is not supported.",
- howToFix: "Try analyzing the code with the --allow-native-extensions "
- "option.",
- examples: const ["""
+ MessageKind.DART_EXT_NOT_SUPPORTED:
+ const MessageTemplate(MessageKind.DART_EXT_NOT_SUPPORTED,
+ "The 'dart-ext' scheme is not supported.",
+ howToFix: "Try analyzing the code with the --allow-native-extensions "
+ "option.",
+ examples: const ["""
import 'dart-ext:main';
main() {}
-"""]);
+"""]),
- static const MessageKind LIBRARY_TAG_MUST_BE_FIRST = const MessageKind(
- "The library declaration should come before other declarations.",
- howToFix: "Try moving the declaration to the top of the file.",
- examples: const [
+ MessageKind.LIBRARY_TAG_MUST_BE_FIRST:
+ const MessageTemplate(MessageKind.LIBRARY_TAG_MUST_BE_FIRST,
+ "The library declaration should come before other declarations.",
+ howToFix: "Try moving the declaration to the top of the file.",
+ examples: const [
"""
import 'dart:core';
library foo;
main() {}
""",
- ]);
+ ]),
- static const MessageKind ONLY_ONE_LIBRARY_TAG = const MessageKind(
- "There can only be one library declaration.",
- howToFix: "Try removing all other library declarations.",
- examples: const [
+ MessageKind.ONLY_ONE_LIBRARY_TAG:
+ const MessageTemplate(MessageKind.ONLY_ONE_LIBRARY_TAG,
+ "There can only be one library declaration.",
+ howToFix: "Try removing all other library declarations.",
+ examples: const [
"""
library foo;
library bar;
@@ -2361,149 +3055,174 @@
library bar;
main() {}
""",
- ]);
+ ]),
- static const MessageKind IMPORT_BEFORE_PARTS = const MessageKind(
- "Import declarations should come before parts.",
- howToFix: "Try moving this import further up in the file.",
- examples: const [
- const <String, String>{
- 'main.dart': """
+ MessageKind.IMPORT_BEFORE_PARTS:
+ const MessageTemplate(MessageKind.IMPORT_BEFORE_PARTS,
+ "Import declarations should come before parts.",
+ howToFix: "Try moving this import further up in the file.",
+ examples: const [
+ const <String, String>{
+ 'main.dart': """
library test.main;
part 'part.dart';
import 'dart:core';
main() {}
""",
- 'part.dart': """
+ 'part.dart': """
part of test.main;
""",
- }]);
+ }]),
- static const MessageKind EXPORT_BEFORE_PARTS = const MessageKind(
- "Export declarations should come before parts.",
- howToFix: "Try moving this export further up in the file.",
- examples: const [
- const <String, String>{
- 'main.dart': """
+ MessageKind.EXPORT_BEFORE_PARTS:
+ const MessageTemplate(MessageKind.EXPORT_BEFORE_PARTS,
+ "Export declarations should come before parts.",
+ howToFix: "Try moving this export further up in the file.",
+ examples: const [
+ const <String, String>{
+ 'main.dart': """
library test.main;
part 'part.dart';
export 'dart:core';
main() {}
""",
- 'part.dart': """
+ 'part.dart': """
part of test.main;
""",
- }]);
+ }]),
//////////////////////////////////////////////////////////////////////////////
// Patch errors start.
//////////////////////////////////////////////////////////////////////////////
- static const MessageKind PATCH_RETURN_TYPE_MISMATCH = const MessageKind(
- "Patch return type '#{patchReturnType}' does not match "
- "'#{originReturnType}' on origin method '#{methodName}'.");
+ MessageKind.PATCH_RETURN_TYPE_MISMATCH:
+ const MessageTemplate(MessageKind.PATCH_RETURN_TYPE_MISMATCH,
+ "Patch return type '#{patchReturnType}' does not match "
+ "'#{originReturnType}' on origin method '#{methodName}'."),
- static const MessageKind PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH =
- const MessageKind(
+ MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH:
+ const MessageTemplate(
+ MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
"Required parameter count of patch method "
"(#{patchParameterCount}) does not match parameter count on origin "
- "method '#{methodName}' (#{originParameterCount}).");
+ "method '#{methodName}' (#{originParameterCount})."),
- static const MessageKind PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH =
- const MessageKind(
+ MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH:
+ const MessageTemplate(
+ MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
"Optional parameter count of patch method "
"(#{patchParameterCount}) does not match parameter count on origin "
- "method '#{methodName}' (#{originParameterCount}).");
+ "method '#{methodName}' (#{originParameterCount})."),
- static const MessageKind PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH =
- const MessageKind(
+ MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH:
+ const MessageTemplate(
+ MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
"Optional parameters of origin and patch method "
- "'#{methodName}' must both be either named or positional.");
+ "'#{methodName}' must both be either named or positional."),
- static const MessageKind PATCH_PARAMETER_MISMATCH = const MessageKind(
- "Patch method parameter '#{patchParameter}' does not match "
- "'#{originParameter}' on origin method '#{methodName}'.");
+ MessageKind.PATCH_PARAMETER_MISMATCH:
+ const MessageTemplate(MessageKind.PATCH_PARAMETER_MISMATCH,
+ "Patch method parameter '#{patchParameter}' does not match "
+ "'#{originParameter}' on origin method '#{methodName}'."),
- static const MessageKind PATCH_PARAMETER_TYPE_MISMATCH = const MessageKind(
- "Patch method parameter '#{parameterName}' type "
- "'#{patchParameterType}' does not match '#{originParameterType}' on "
- "origin method '#{methodName}'.");
+ MessageKind.PATCH_PARAMETER_TYPE_MISMATCH:
+ const MessageTemplate(MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
+ "Patch method parameter '#{parameterName}' type "
+ "'#{patchParameterType}' does not match '#{originParameterType}' on "
+ "origin method '#{methodName}'."),
- static const MessageKind PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION =
- const MessageKind("External method without an implementation.");
+ MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION:
+ const MessageTemplate(MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION,
+ "External method without an implementation."),
- static const MessageKind PATCH_POINT_TO_FUNCTION = const MessageKind(
- "This is the function patch '#{functionName}'.");
+ MessageKind.PATCH_POINT_TO_FUNCTION:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_FUNCTION,
+ "This is the function patch '#{functionName}'."),
- static const MessageKind PATCH_POINT_TO_CLASS = const MessageKind(
- "This is the class patch '#{className}'.");
+ MessageKind.PATCH_POINT_TO_CLASS:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_CLASS,
+ "This is the class patch '#{className}'."),
- static const MessageKind PATCH_POINT_TO_GETTER = const MessageKind(
- "This is the getter patch '#{getterName}'.");
+ MessageKind.PATCH_POINT_TO_GETTER:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_GETTER,
+ "This is the getter patch '#{getterName}'."),
- static const MessageKind PATCH_POINT_TO_SETTER = const MessageKind(
- "This is the setter patch '#{setterName}'.");
+ MessageKind.PATCH_POINT_TO_SETTER:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_SETTER,
+ "This is the setter patch '#{setterName}'."),
- static const MessageKind PATCH_POINT_TO_CONSTRUCTOR = const MessageKind(
- "This is the constructor patch '#{constructorName}'.");
+ MessageKind.PATCH_POINT_TO_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_CONSTRUCTOR,
+ "This is the constructor patch '#{constructorName}'."),
- static const MessageKind PATCH_POINT_TO_PARAMETER = const MessageKind(
- "This is the patch parameter '#{parameterName}'.");
+ MessageKind.PATCH_POINT_TO_PARAMETER:
+ const MessageTemplate(MessageKind.PATCH_POINT_TO_PARAMETER,
+ "This is the patch parameter '#{parameterName}'."),
- static const MessageKind PATCH_NON_EXISTING = const MessageKind(
- "Origin does not exist for patch '#{name}'.");
+ MessageKind.PATCH_NON_EXISTING:
+ const MessageTemplate(MessageKind.PATCH_NON_EXISTING,
+ "Origin does not exist for patch '#{name}'."),
- // TODO(ahe): Eventually, this error should be removed as it will be handled
- // by the regular parser.
- static const MessageKind PATCH_NONPATCHABLE = const MessageKind(
- "Only classes and functions can be patched.");
+ // TODO(ahe): Eventually, this error should be removed as it will be
+ // handled by the regular parser.
+ MessageKind.PATCH_NONPATCHABLE:
+ const MessageTemplate(MessageKind.PATCH_NONPATCHABLE,
+ "Only classes and functions can be patched."),
- static const MessageKind PATCH_NON_EXTERNAL = const MessageKind(
- "Only external functions can be patched.");
+ MessageKind.PATCH_NON_EXTERNAL:
+ const MessageTemplate(MessageKind.PATCH_NON_EXTERNAL,
+ "Only external functions can be patched."),
- static const MessageKind PATCH_NON_CLASS = const MessageKind(
- "Patching non-class with class patch '#{className}'.");
+ MessageKind.PATCH_NON_CLASS:
+ const MessageTemplate(MessageKind.PATCH_NON_CLASS,
+ "Patching non-class with class patch '#{className}'."),
- static const MessageKind PATCH_NON_GETTER = const MessageKind(
- "Cannot patch non-getter '#{name}' with getter patch.");
+ MessageKind.PATCH_NON_GETTER:
+ const MessageTemplate(MessageKind.PATCH_NON_GETTER,
+ "Cannot patch non-getter '#{name}' with getter patch."),
- static const MessageKind PATCH_NO_GETTER = const MessageKind(
- "No getter found for getter patch '#{getterName}'.");
+ MessageKind.PATCH_NO_GETTER:
+ const MessageTemplate(MessageKind.PATCH_NO_GETTER,
+ "No getter found for getter patch '#{getterName}'."),
- static const MessageKind PATCH_NON_SETTER = const MessageKind(
- "Cannot patch non-setter '#{name}' with setter patch.");
+ MessageKind.PATCH_NON_SETTER:
+ const MessageTemplate(MessageKind.PATCH_NON_SETTER,
+ "Cannot patch non-setter '#{name}' with setter patch."),
- static const MessageKind PATCH_NO_SETTER = const MessageKind(
- "No setter found for setter patch '#{setterName}'.");
+ MessageKind.PATCH_NO_SETTER:
+ const MessageTemplate(MessageKind.PATCH_NO_SETTER,
+ "No setter found for setter patch '#{setterName}'."),
- static const MessageKind PATCH_NON_CONSTRUCTOR = const MessageKind(
- "Cannot patch non-constructor with constructor patch "
- "'#{constructorName}'.");
+ MessageKind.PATCH_NON_CONSTRUCTOR:
+ const MessageTemplate(MessageKind.PATCH_NON_CONSTRUCTOR,
+ "Cannot patch non-constructor with constructor patch "
+ "'#{constructorName}'."),
- static const MessageKind PATCH_NON_FUNCTION = const MessageKind(
- "Cannot patch non-function with function patch "
- "'#{functionName}'.");
+ MessageKind.PATCH_NON_FUNCTION:
+ const MessageTemplate(MessageKind.PATCH_NON_FUNCTION,
+ "Cannot patch non-function with function patch "
+ "'#{functionName}'."),
- static const MessageKind EXTERNAL_WITH_BODY = const MessageKind(
- "External function '#{functionName}' cannot have a function body.",
- options: const ["--output-type=dart"],
- howToFix: "Try removing the 'external' modifier or the function body.",
- examples: const ["""
+ MessageKind.EXTERNAL_WITH_BODY:
+ const MessageTemplate(MessageKind.EXTERNAL_WITH_BODY,
+ "External function '#{functionName}' cannot have a function body.",
+ options: const ["--output-type=dart"],
+ howToFix:
+ "Try removing the 'external' modifier or the function body.",
+ examples: const ["""
external foo() => 0;
main() => foo();
""", """
external foo() {}
main() => foo();
-"""]);
+"""]),
//////////////////////////////////////////////////////////////////////////////
// Patch errors end.
//////////////////////////////////////////////////////////////////////////////
- static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n* ';
-
- static const MessageKind IMPORT_EXPERIMENTAL_MIRRORS =
- const MessageKind(r'''
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS:
+ const MessageTemplate(MessageKind.IMPORT_EXPERIMENTAL_MIRRORS, r'''
****************************************************************
* WARNING: dart:mirrors support in dart2js is experimental,
@@ -2521,39 +3240,45 @@
* To learn what to do next, please visit:
* http://dartlang.org/dart2js-reflection
****************************************************************
-''');
+'''),
- static const MessageKind MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND =
- const MessageKind(
- "dart:mirrors library is not supported when using this backend.");
+ MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
+ const MessageTemplate(
+ MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+ "dart:mirrors library is not supported when using this backend."),
- static const MessageKind CALL_NOT_SUPPORTED_ON_NATIVE_CLASS =
- const MessageKind(
+ MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
+ const MessageTemplate(MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
"Non-supported 'call' member on a native class, or a "
- "subclass of a native class.");
+ "subclass of a native class."),
- static const MessageKind DIRECTLY_THROWING_NSM =
- const MessageKind(
+ MessageKind.DIRECTLY_THROWING_NSM:
+ const MessageTemplate(MessageKind.DIRECTLY_THROWING_NSM,
"This 'noSuchMethod' implementation is guaranteed to throw an "
"exception. The generated code will be smaller if it is "
"rewritten.",
howToFix: "Rewrite to "
- "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.");
+ "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'."),
- static const MessageKind COMPLEX_THROWING_NSM =
- const MessageKind(
+ MessageKind.COMPLEX_THROWING_NSM:
+ const MessageTemplate(MessageKind.COMPLEX_THROWING_NSM,
"This 'noSuchMethod' implementation is guaranteed to throw an "
"exception. The generated code will be smaller and the compiler "
"will be able to perform more optimizations if it is rewritten.",
howToFix: "Rewrite to "
- "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.");
+ "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'."),
- static const MessageKind COMPLEX_RETURNING_NSM =
- const MessageKind(
+ MessageKind.COMPLEX_RETURNING_NSM:
+ const MessageTemplate(MessageKind.COMPLEX_RETURNING_NSM,
"Overriding 'noSuchMethod' causes the compiler to generate "
"more code and prevents the compiler from doing some optimizations.",
- howToFix: "Consider removing this 'noSuchMethod' implementation.");
+ howToFix: "Consider removing this 'noSuchMethod' implementation."),
+
+
+ }; // End of TEMPLATES.
+
+ static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n* ';
toString() => template;
@@ -2565,18 +3290,20 @@
}
class Message {
- final MessageKind kind;
+ final MessageTemplate template;
final Map arguments;
final bool terse;
String message;
- Message(this.kind, this.arguments, this.terse) {
+ Message(this.template, this.arguments, this.terse) {
assert(() { computeMessage(); return true; });
}
+ MessageKind get kind => template.kind;
+
String computeMessage() {
if (message == null) {
- message = kind.template;
+ message = template.template;
arguments.forEach((key, value) {
message = message.replaceAll('#{${key}}', convertToString(value));
});
@@ -2585,8 +3312,8 @@
kind == MessageKind.GENERIC ||
!message.contains(new RegExp(r'#\{.+\}')),
message: 'Missing arguments in error message: "$message"'));
- if (!terse && kind.hasHowToFix) {
- String howToFix = kind.howToFix;
+ if (!terse && template.hasHowToFix) {
+ String howToFix = template.howToFix;
arguments.forEach((key, value) {
howToFix = howToFix.replaceAll('#{${key}}', convertToString(value));
});
@@ -2602,7 +3329,7 @@
bool operator==(other) {
if (other is !Message) return false;
- return (kind == other.kind) && (toString() == other.toString());
+ return (template == other.template) && (toString() == other.toString());
}
int get hashCode => throw new UnsupportedError('Message.hashCode');
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index b4d78dd..68d0f4d 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -46,6 +46,10 @@
/// instance of [y].
bool isSubtypeOf(ClassElement x, ClassElement y);
+ /// Returns an iterable over the live classes that extend [cls] including
+ /// [cls] itself.
+ Iterable<ClassElement> subclassesOf(ClassElement cls);
+
/// Returns an iterable over the live classes that extend [cls] _not_
/// including [cls] itself.
Iterable<ClassElement> strictSubclassesOf(ClassElement cls);
@@ -145,34 +149,51 @@
return compiler.resolverWorld.isInstantiated(cls);
}
- /// Returns an iterable over the live classes that extend [cls] _not_
- /// including [cls] itself.
+ /// Returns an iterable over the directly instantiated classes that extend
+ /// [cls] possibly including [cls] itself, if it is live.
+ Iterable<ClassElement> subclassesOf(ClassElement cls) {
+ ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration];
+ if (hierarchy == null) return const <ClassElement>[];
+ assert(invariant(cls, isInstantiated(cls.declaration),
+ message: 'Class $cls has not been instantiated.'));
+ return hierarchy.subclasses();
+ }
+
+ /// Returns an iterable over the directly instantiated classes that extend
+ /// [cls] _not_ including [cls] itself.
Iterable<ClassElement> strictSubclassesOf(ClassElement cls) {
- Set<ClassElement> subclasses = _subclasses[cls.declaration];
+ ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
if (subclasses == null) return const <ClassElement>[];
assert(invariant(cls, isInstantiated(cls.declaration),
message: 'Class $cls has not been instantiated.'));
- return subclasses;
+ return subclasses.strictSubclasses();
}
- /// Returns an iterable over the live classes that implement [cls] _not_
- /// including [cls] if it is live.
+ /// Returns an iterable over the directly instantiated that implement [cls]
+ /// _not_ including [cls].
Iterable<ClassElement> strictSubtypesOf(ClassElement cls) {
Set<ClassElement> subtypes = _subtypes[cls.declaration];
return subtypes != null ? subtypes : const <ClassElement>[];
}
- /// Returns `true` if any live class other than [cls] extends [cls].
+ /// Returns `true` if any directly instantiated class other than [cls] extends
+ /// [cls].
bool hasAnyStrictSubclass(ClassElement cls) {
- return !strictSubclassesOf(cls).isEmpty;
+ ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+ if (subclasses == null) return false;
+ assert(invariant(cls, isInstantiated(cls.declaration),
+ message: 'Class $cls has not been instantiated.'));
+ return subclasses.isIndirectlyInstantiated;
}
- /// Returns `true` if any live class other than [cls] implements [cls].
+ /// Returns `true` if any directly instantiated class other than [cls]
+ /// implements [cls].
bool hasAnyStrictSubtype(ClassElement cls) {
return !strictSubtypesOf(cls).isEmpty;
}
- /// Returns `true` if all live classes that implement [cls] extend it.
+ /// Returns `true` if all directly instantiated classes that implement [cls]
+ /// extend it.
bool hasOnlySubclasses(ClassElement cls) {
Iterable<ClassElement> subtypes = strictSubtypesOf(cls);
if (subtypes == null) return true;
@@ -284,8 +305,8 @@
// We keep track of subtype and subclass relationships in four
// distinct sets to make class hierarchy analysis faster.
- final Map<ClassElement, Set<ClassElement>> _subclasses =
- new Map<ClassElement, Set<ClassElement>>();
+ final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes =
+ <ClassElement, ClassHierarchyNode>{};
final Map<ClassElement, Set<ClassElement>> _subtypes =
new Map<ClassElement, Set<ClassElement>>();
@@ -319,7 +340,40 @@
this.compiler = compiler,
alreadyPopulated = compiler.cacheStrategy.newSet();
+ ClassHierarchyNode classHierarchyNode(ClassElement cls) {
+ return _classHierarchyNodes[cls];
+ }
+
void populate() {
+
+ /// Ensure that a [ClassHierarchyNode] exists for [cls]. Updates the
+ /// `isDirectlyInstantiated` and `isIndirectlyInstantiated` property of the
+ /// node according the provided arguments and returns the node.
+ ClassHierarchyNode createClassHierarchyNodeForClass(
+ ClassElement cls,
+ {bool directlyInstantiated: false,
+ bool indirectlyInstantiated: false}) {
+ assert(isInstantiated(cls));
+
+ ClassHierarchyNode node = _classHierarchyNodes.putIfAbsent(cls, () {
+ ClassHierarchyNode node = new ClassHierarchyNode(cls);
+ if (cls.superclass != null) {
+ createClassHierarchyNodeForClass(cls.superclass,
+ indirectlyInstantiated:
+ directlyInstantiated || indirectlyInstantiated)
+ .addDirectSubclass(node);
+ }
+ return node;
+ });
+ if (directlyInstantiated) {
+ node.isDirectlyInstantiated = true;
+ }
+ if (indirectlyInstantiated) {
+ node.isIndirectlyInstantiated = true;
+ }
+ return node;
+ }
+
void addSubtypes(ClassElement cls) {
if (compiler.hasIncrementalSupport && !alreadyPopulated.add(cls)) {
return;
@@ -329,6 +383,8 @@
compiler.internalError(cls, 'Class "${cls.name}" is not resolved.');
}
+ createClassHierarchyNodeForClass(cls, directlyInstantiated: true);
+
for (DartType type in cls.allSupertypes) {
Set<Element> subtypesOfSupertype =
_subtypes.putIfAbsent(type.element, () => new Set<ClassElement>());
@@ -339,10 +395,6 @@
// implemented by that type on the superclasses.
ClassElement superclass = cls.superclass;
while (superclass != null) {
- Set<Element> subclassesOfSuperclass =
- _subclasses.putIfAbsent(superclass, () => new Set<ClassElement>());
- subclassesOfSuperclass.add(cls);
-
Set<Element> typesImplementedBySubclassesOfCls =
_typesImplementedBySubclasses.putIfAbsent(
superclass, () => new Set<ClassElement>());
diff --git a/pkg/js_ast/lib/src/builder.dart b/pkg/js_ast/lib/src/builder.dart
index 076ff65..67ea25c 100644
--- a/pkg/js_ast/lib/src/builder.dart
+++ b/pkg/js_ast/lib/src/builder.dart
@@ -377,6 +377,14 @@
List<Expression> arguments) {
return new Call(new PropertyAccess(receiver, fieldName), arguments);
}
+
+ ObjectInitializer objectLiteral(Map<String, Expression> map) {
+ List<Property> properties = <Property>[];
+ map.forEach((name, value) {
+ properties.add(new Property(string(name), value));
+ });
+ return new ObjectInitializer(properties);
+ }
}
LiteralString string(String value) => js.string(value);
@@ -400,6 +408,9 @@
List<Expression> arguments) {
return js.propertyCall(receiver, fieldName, arguments);
}
+ObjectInitializer objectLiteral(Map<String, Expression> map) {
+ return js.objectLiteral(map);
+}
class MiniJsParserError {
MiniJsParserError(this.parser, this.message) { }
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d5a359a..e98d307 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -88,8 +88,10 @@
analyzer/test/generated/incremental_resolver_test: Pass, Slow # Issue 21628
analyzer/test/generated/utilities_test: Pass, Slow # Issue 21628
analyzer/test/generated/parser_test: Pass, Slow # Issue 21628
+analyzer/test/generated/scanner_test: Pass, Slow # Issue 21628
analyzer/test/src/task/dart_test: Pass, Slow # Issue 21628
analyzer/test/src/task/driver_test: Pass, Slow # Issue 21628
+analyzer/test/src/context/cache_test: Pass, Slow # Issue 21628
[ $runtime == jsshell ]
async/test/stream_zip_test: RuntimeError, OK # Timers are not supported.
@@ -151,44 +153,9 @@
analyzer/test/*: PubGetError
[ $compiler == dart2js && $cps_ir ]
-analyzer/test/cancelable_future_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/enum_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/file_system/memory_file_system_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/file_system/physical_resource_provider_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/file_system/resource_uri_resolver_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/all_the_rest_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/ast_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/compile_time_error_code_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/element_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/incremental_resolver_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/incremental_scanner_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/non_error_resolver_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/parser_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/resolver_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/scanner_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/source_factory_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/static_type_warning_code_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/static_warning_code_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/type_system_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/generated/utilities_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/instrumentation/instrumentation_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/parse_compilation_unit_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/source/analysis_options_provider_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/source/package_map_provider_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/source/package_map_resolver_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/source/sdk_ext_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/context/cache_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/context/context_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/dart_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/dart_work_manager_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/driver_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/general_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/html_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/html_work_manager_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/incremental_element_builder_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/inputs_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/manager_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/task/model_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/util/asserts_test: Crash # The null object does not have a getter '_element'.
-analyzer/test/src/util/lru_map_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/cancelable_future_test: Crash # Invalid argument(s)
+analyzer/test/enum_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
+analyzer/test/file_system/physical_resource_provider_test: Crash # (Future _poll()async... cannot handle async/sync*/async* functions
+analyzer/test/generated/all_the_rest_test: Crash # (Future test_implici... cannot handle async/sync*/async* functions
+analyzer/test/src/context/context_test: Crash # Invalid argument(s)
typed_data/test/typed_buffers_test/none: RuntimeError # Please triage this failure.
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 7caf19b..00c9f69 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -498,7 +498,6 @@
'../tools/create_resources.py',
# The following two files are used to trigger a rebuild.
'<(PRODUCT_DIR)/observatory/deployed/web/index.html',
- '<(PRODUCT_DIR)/observatory/deployed/web/index.html.polymer.bootstrap.dart.js',
'<@(_sources)',
],
'outputs': [
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 940556a..d678665 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -4,10 +4,18 @@
library builtin;
// NOTE: Do not import 'dart:io' in builtin.
+import 'dart:async';
import 'dart:collection';
+import 'dart:_internal';
import 'dart:isolate';
import 'dart:typed_data';
+
+// Before handling an embedder entrypoint we finalize the setup of the
+// dart:_builtin library.
+bool _setupCompleted = false;
+
+
// The root library (aka the script) is imported into this library. The
// standalone embedder uses this to lookup the main entrypoint in the
// root library's namespace.
@@ -49,10 +57,11 @@
// The embedder forwards most loading requests to this library.
// See Dart_LibraryTag in dart_api.h
-const Dart_kScriptTag = null;
-const Dart_kImportTag = 0;
-const Dart_kSourceTag = 1;
-const Dart_kCanonicalizeUrl = 2;
+const _Dart_kScriptTag = null;
+const _Dart_kImportTag = 0;
+const _Dart_kSourceTag = 1;
+const _Dart_kCanonicalizeUrl = 2;
+const _Dart_kResourceLoad = 3;
// Embedder sets this to true if the --trace-loading flag was passed on the
// command line.
@@ -78,15 +87,32 @@
// package imports can be resolved relative to it. The root script is the basis
// for the root library in the VM.
Uri _rootScript;
+
+// Packages are either resolved looking up in a map or resolved from within a
+// package root.
+bool _packagesReady() => (_packageRoot != null) || (_packageMap != null);
// The directory to look in to resolve "package:" scheme URIs. By detault it is
// the 'packages' directory right next to the script.
-Uri _packageRoot = _rootScript.resolve('packages/');
+Uri _packageRoot = null; // Used to be _rootScript.resolve('packages/');
+// The map describing how certain package names are mapped to Uris.
+Map<String, Uri> _packageMap = null;
+// A list of pending packags which have been requested while resolving the
+// location of the package root or the contents of the package map.
+List<_LoadRequest> _pendingPackageLoads = [];
+
+// If we have outstanding loads or pending package loads waiting for resolution,
+// then we do have pending loads.
+bool _pendingLoads() => !_reqMap.isEmpty || !_pendingPackageLoads.isEmpty;
// Special handling for Windows paths so that they are compatible with URI
// handling.
// Embedder sets this to true if we are running on Windows.
bool _isWindows = false;
+// Logging from builtin.dart is prefixed with a '*'.
+_log(msg) {
+ _print("* $msg");
+}
// A class wrapping the load error message in an Error object.
class _LoadError extends Error {
@@ -102,9 +128,16 @@
final int _id;
final int _tag;
final String _uri;
- final String _libraryUri;
+ final Uri _resourceUri;
+ final _context;
- _LoadRequest(this._id, this._tag, this._uri, this._libraryUri);
+ _LoadRequest(this._id,
+ this._tag,
+ this._uri,
+ this._resourceUri,
+ this._context);
+
+ toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)";
}
@@ -171,12 +204,15 @@
// Embedder Entrypoint:
// The embedder calls this method with the current working directory.
void _setWorkingDirectory(cwd) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
if (_traceLoading) {
- _print('# Setting working directory: $cwd');
+ _log('Setting working directory: $cwd');
}
_workingDirectory = new Uri.directory(cwd);
if (_traceLoading) {
- _print('# Working directory URI: $_workingDirectory');
+ _log('Working directory URI: $_workingDirectory');
}
}
@@ -184,8 +220,11 @@
// Embedder Entrypoint:
// The embedder calls this method with a custom package root.
_setPackageRoot(String packageRoot) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
if (_traceLoading) {
- _print('# Setting package root: $packageRoot');
+ _log('Setting package root: $packageRoot');
}
packageRoot = _enforceTrailingSlash(packageRoot);
if (packageRoot.startsWith('file:') ||
@@ -198,7 +237,7 @@
_packageRoot = _workingDirectory.resolveUri(new Uri.file(packageRoot));
}
if (_traceLoading) {
- _print('# Package root URI: $_packageRoot');
+ _log('Package root URI: $_packageRoot');
}
}
@@ -216,16 +255,36 @@
}
if (_traceLoading) {
- _print('# Package root: $_packageRoot');
- _print('# uri path: ${uri.path}');
+ _log('Resolving package with uri path: ${uri.path}');
}
- return _packageRoot.resolve(uri.path);
+ var resolvedUri;
+ if (_packageRoot != null) {
+ resolvedUri = _packageRoot.resolve(uri.path);
+ } else {
+ var packageName = uri.pathSegments[0];
+ var mapping = _packageMap[packageName];
+ if (_traceLoading) {
+ _log("Mapped '$packageName' package to '$mapping'");
+ }
+ if (mapping == null) {
+ throw "No mapping for '$packageName' package when resolving '$uri'.";
+ }
+ var path = uri.path.substring(packageName.length + 1);
+ resolvedUri = mapping.resolve(path);
+ }
+ if (_traceLoading) {
+ _log("Resolved '$uri' to '$resolvedUri'.");
+ }
+ return resolvedUri;
}
// Resolves the script uri in the current working directory iff the given uri
// did not specify a scheme (e.g. a path to a script file on the command line).
Uri _resolveScriptUri(String scriptName) {
+ if (_traceLoading) {
+ _log("Resolving script: $scriptName");
+ }
if (_workingDirectory == null) {
throw 'No current working directory set.';
}
@@ -243,7 +302,7 @@
_rootScript = scriptUri;
if (_traceLoading) {
- _print('# Resolved entry point to: $_rootScript');
+ _log('Resolved entry point to: $_rootScript');
}
return scriptUri;
}
@@ -254,13 +313,14 @@
var tmp = _reqMap.remove(req._id);
assert(tmp == req);
if (_traceLoading) {
- _print("Loading of ${req._uri} finished, "
- "${_reqMap.length} requests remaining");
+ _log("Loading of ${req._uri} finished: "
+ "${_reqMap.length} requests remaining, "
+ "${_pendingPackageLoads.length} packages pending.");
}
- if (_reqMap.isEmpty) {
+ if (!_pendingLoads()) {
if (_traceLoading) {
- _print("Closing loading port.");
+ _log("Closing loading port.");
}
_receivePort.close();
_receivePort = null;
@@ -278,29 +338,36 @@
var req = _reqMap[id];
try {
if (dataOrError is Uint8List) {
- _loadScript(req, dataOrError);
+ // Successfully loaded the data.
+ if (req._tag == _Dart_kResourceLoad) {
+ Completer c = req._context;
+ c.complete(dataOrError);
+ } else {
+ // TODO: Currently a compilation error while loading the script is
+ // fatal for the isolate. _loadScriptCallback() does not return and
+ // the number of requests remains out of sync.
+ _loadScriptCallback(req._tag, req._uri, req._context, dataOrError);
+ }
+ _finishLoadRequest(req);
} else {
assert(dataOrError is String);
var error = new _LoadError(req._uri, dataOrError.toString());
- _asyncLoadError(req, error);
+ _asyncLoadError(req, error, null);
}
} catch(e, s) {
// Wrap inside a _LoadError unless we are already propagating a
// previous _LoadError.
var error = (e is _LoadError) ? e : new _LoadError(req._uri, e.toString());
assert(req != null);
- _asyncLoadError(req, error);
+ _asyncLoadError(req, error, s);
}
}
-void _startLoadRequest(int tag,
- String uri,
- String libraryUri,
- Uri resourceUri) {
- if (_reqMap.isEmpty) {
+void _startLoadRequest(int tag, String uri, Uri resourceUri, context) {
+ if (_receivePort == null) {
if (_traceLoading) {
- _print("Initializing load port.");
+ _log("Initializing load port.");
}
assert(_receivePort == null);
assert(_sendPort == null);
@@ -311,59 +378,213 @@
var curId = _reqId++;
assert(_reqMap[curId] == null);
- _reqMap[curId] = new _LoadRequest(curId, tag, uri, libraryUri);
+ _reqMap[curId] = new _LoadRequest(curId, tag, uri, resourceUri, context);
- var msg = new List(3);
+ assert(_receivePort != null);
+ assert(_sendPort != null);
+
+ var msg = new List(4);
msg[0] = _sendPort;
- msg[1] = curId;
- msg[2] = resourceUri.toString();
+ msg[1] = _traceLoading;
+ msg[2] = curId;
+ msg[3] = resourceUri.toString();
_loadPort.send(msg);
if (_traceLoading) {
- _print("Loading of $resourceUri for $uri started with id: $curId, "
- "${_reqMap.length} requests outstanding");
+ _log("Loading of $resourceUri for $uri started with id: $curId. "
+ "${_reqMap.length} requests remaining, "
+ "${_pendingPackageLoads.length} packages pending.");
}
}
-void _loadScript(_LoadRequest req, Uint8List data) {
- // TODO: Currently a compilation error while loading the script is
- // fatal for the isolate. _loadScriptCallback() does not return and
- // the number of requests remains out of sync.
- _loadScriptCallback(req._tag, req._uri, req._libraryUri, data);
- _finishLoadRequest(req);
-}
+RawReceivePort _packagesPort;
+void _handlePackagesReply(msg) {
+ // Make sure to close the _packagePort before any other action.
+ _packagesPort.close();
-void _asyncLoadError(_LoadRequest req, _LoadError error) {
if (_traceLoading) {
- _print("_asyncLoadError(${req._uri}), error: $error");
+ _log("Got packages reply: $msg");
}
- var libraryUri = req._libraryUri;
- if (req._tag == Dart_kImportTag) {
- // When importing a library, the libraryUri is the imported
- // uri.
- libraryUri = req._uri;
+ if (msg is String) {
+ if (_traceLoading) {
+ _log("Got failure response on package port: '$msg'");
+ }
+ throw msg;
}
- _asyncLoadErrorCallback(req._uri, libraryUri, error);
+ if (msg.length == 1) {
+ if (_traceLoading) {
+ _log("Received package root: '${msg[0]}'");
+ }
+ _packageRoot = Uri.parse(msg[0]);
+ } else {
+ assert((msg.length % 2) == 0);
+ _packageMap = new Map<String, Uri>();
+ for (var i = 0; i < msg.length; i+=2) {
+ // TODO(iposva): Complain about duplicate entries.
+ _packageMap[msg[i]] = Uri.parse(msg[i+1]);
+ }
+ if (_traceLoading) {
+ _log("Setup package map: $_packageMap");
+ }
+ }
+
+ // Resolve all pending package loads now that we know how to resolve them.
+ while (_pendingPackageLoads.length > 0) {
+ var req = _pendingPackageLoads.removeLast();
+ if (req != null) {
+ if (_traceLoading) {
+ _log("Handling deferred load request: $req");
+ }
+ _loadPackage(req._tag, req._uri, req._resourceUri, req._context);
+ } else {
+ if (_traceLoading) {
+ _log("Skipping dummy deferred request.");
+ }
+ }
+ }
+ // Reset the pending package loads to empty. So that we eventually can
+ // finish loading.
+ _pendingPackageLoads = [];
+}
+
+
+void _requestPackagesMap() {
+ assert(_packagesPort == null);
+ assert(_rootScript != null);
+ // Create a port to receive the packages map on.
+ _packagesPort = new RawReceivePort(_handlePackagesReply);
+ var sp = _packagesPort.sendPort;
+
+ var msg = new List(4);
+ msg[0] = sp;
+ msg[1] = _traceLoading;
+ msg[2] = -1;
+ msg[3] = _rootScript.toString();
+ _loadPort.send(msg);
+
+ if (_traceLoading) {
+ _log("Requested packages map for '$_rootScript'.");
+ }
+}
+
+
+// Embedder Entrypoint:
+// Request the load of a particular packages map.
+void _loadPackagesMap(String packagesParam) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
+ // First convert the packages parameter from the command line to a URI which
+ // can be handled by the loader code.
+ // TODO(iposva): Consider refactoring the common code below which is almost
+ // shared with resolution of the root script.
+ if (_traceLoading) {
+ _log("Resolving packages map: $packagesParam");
+ }
+ if (_workingDirectory == null) {
+ throw 'No current working directory set.';
+ }
+ var packagesName = _sanitizeWindowsPath(packagesParam);
+ var packagesUri = Uri.parse(packagesName);
+ if (packagesUri.scheme == '') {
+ // Script does not have a scheme, assume that it is a path,
+ // resolve it against the working directory.
+ packagesUri = _workingDirectory.resolveUri(packagesUri);
+ }
+ if (_traceLoading) {
+ _log('Resolved packages map to: $packagesUri');
+ }
+
+ // Request the loading and parsing of the packages map at the specified URI.
+ // Create a port to receive the packages map on.
+ assert(_packagesPort == null);
+ _packagesPort = new RawReceivePort(_handlePackagesReply);
+ var sp = _packagesPort.sendPort;
+
+ var msg = new List(4);
+ msg[0] = sp;
+ msg[1] = _traceLoading;
+ msg[2] = -2;
+ msg[3] = packagesUri.toString();
+ _loadPort.send(msg);
+
+ // Signal that the resolution of the packages map has started. But in this
+ // case it is not tied to a particular request.
+ _pendingPackageLoads.add(null);
+
+ if (_traceLoading) {
+ _log("Requested packages map at '$packagesUri'.");
+ }
+}
+
+
+void _asyncLoadError(_LoadRequest req, _LoadError error, StackTrace stack) {
+ if (_traceLoading) {
+ _log("_asyncLoadError(${req._uri}), error: $error\nstack: $stack");
+ }
+ if (req._tag == _Dart_kResourceLoad) {
+ Completer c = req._context;
+ c.completeError(error, stack);
+ } else {
+ String libraryUri = req._context;
+ if (req._tag == _Dart_kImportTag) {
+ // When importing a library, the libraryUri is the imported
+ // uri.
+ libraryUri = req._uri;
+ }
+ _asyncLoadErrorCallback(req._uri, libraryUri, error);
+ }
_finishLoadRequest(req);
}
-_loadDataFromLoadPort(int tag,
- String uri,
- String libraryUri,
- Uri resourceUri) {
+_loadDataFromLoadPort(int tag, String uri, Uri resourceUri, context) {
try {
- _startLoadRequest(tag, uri, libraryUri, resourceUri);
- } catch (e) {
+ _startLoadRequest(tag, uri, resourceUri, context);
+ } catch (e, s) {
if (_traceLoading) {
- _print("Exception when communicating with service isolate: $e");
+ _log("Exception when communicating with service isolate: $e");
}
// Wrap inside a _LoadError unless we are already propagating a previously
// seen _LoadError.
var error = (e is _LoadError) ? e : new _LoadError(e.toString());
- _asyncLoadError(tag, uri, libraryUri, error);
+ _asyncLoadError(tag, uri, context, error, s);
+ }
+}
+
+
+// Loading a package URI needs to first map the package name to a loadable
+// URI.
+_loadPackage(int tag, String uri, Uri resourceUri, context) {
+ if (_packagesReady()) {
+ _loadData(tag, uri, _resolvePackageUri(resourceUri), context);
+ } else {
+ if (_pendingPackageLoads.isEmpty) {
+ // Package resolution has not been setup yet, and this is the first
+ // request for package resolution & loading.
+ _requestPackagesMap();
+ }
+ var req = new _LoadRequest(-1, tag, uri, resourceUri, context);
+ _pendingPackageLoads.add(req);
+ if (_traceLoading) {
+ _log("Pending package load of '$uri': "
+ "${_pendingPackageLoads.length} pending");
+ }
+ }
+}
+
+
+// Load the data associated with the resourceUri.
+_loadData(int tag, String uri, Uri resourceUri, context) {
+ if (resourceUri.scheme == 'package') {
+ // package based uris need to be resolved to the correct loadable location.
+ // The logic of which is handled seperately, and then _loadData is called
+ // recursively.
+ _loadPackage(tag, uri, resourceUri, context);
+ } else {
+ _loadDataFromLoadPort(tag, uri, resourceUri, context);
}
}
@@ -371,20 +592,17 @@
// Embedder Entrypoint:
// Asynchronously loads script data through a http[s] or file uri.
_loadDataAsync(int tag, String uri, String libraryUri) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
var resourceUri;
- if (tag == Dart_kScriptTag) {
+ if (tag == _Dart_kScriptTag) {
resourceUri = _resolveScriptUri(uri);
uri = resourceUri.toString();
} else {
resourceUri = Uri.parse(uri);
}
-
- // package based uris need to be resolved to the correct loadable location.
- if (resourceUri.scheme == 'package') {
- resourceUri = _resolvePackageUri(resourceUri);
- }
-
- _loadDataFromLoadPort(tag, uri, libraryUri, resourceUri);
+ _loadData(tag, uri, resourceUri, libraryUri);
}
@@ -392,8 +610,11 @@
// Function called by standalone embedder to resolve uris when the VM requests
// Dart_kCanonicalizeUrl from the tag handler.
String _resolveUri(String base, String userString) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
if (_traceLoading) {
- _print('# Resolving: $userString from $base');
+ _log('Resolving: $userString from $base');
}
var baseUri = Uri.parse(base);
var result;
@@ -404,15 +625,29 @@
result = baseUri.resolve(userString).toString();
}
if (_traceLoading) {
- _print('Resolved $userString in $base to $result');
+ _log('Resolved $userString in $base to $result');
}
return result;
}
+// Handling of Resource class by dispatching to the load port.
+Future<List<int>> _resourceReadAsBytes(Uri uri) {
+ var completer = new Completer<List<int>>();
+ // Request the load of the resource associating the completer as the context
+ // for the load.
+ _loadData(_Dart_kResourceLoad, uri.toString(), uri, completer);
+ // Return the future that will be triggered once the resource has been loaded.
+ return completer.future;
+}
+
+
// Embedder Entrypoint (gen_snapshot):
// Resolve relative paths relative to working directory.
String _resolveInWorkingDirectory(String fileName) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
if (_workingDirectory == null) {
throw 'No current working directory set.';
}
@@ -425,7 +660,7 @@
uri = _workingDirectory.resolveUri(uri);
if (_traceLoading) {
- _print('# Resolved in working directory: $fileName -> $uri');
+ _log('Resolved in working directory: $fileName -> $uri');
}
return uri.toString();
}
@@ -453,7 +688,7 @@
String _filePathFromUri(String userUri) {
var uri = Uri.parse(userUri);
if (_traceLoading) {
- _print('# Getting file path from: $uri');
+ _log('Getting file path from: $uri');
}
var path;
@@ -471,7 +706,7 @@
// Only handling file, http, and package URIs
// in standalone binary.
if (_traceLoading) {
- _print('# Unknown scheme (${uri.scheme}) in $uri.');
+ _log('Unknown scheme (${uri.scheme}) in $uri.');
}
throw 'Not a known scheme: $uri';
}
@@ -487,6 +722,9 @@
// The filename part is the extension name, with the platform-dependent
// prefixes and extensions added.
_extensionPathFromUri(String userUri) {
+ if (!_setupCompleted) {
+ _setupHooks();
+ }
if (!userUri.startsWith(_DART_EXT)) {
throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:';
}
@@ -514,3 +752,10 @@
return [path, filename, name];
}
+
+
+// Register callbacks and hooks with the rest of the core libraries.
+_setupHooks() {
+ _setupCompleted = true;
+ VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes;
+}
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index 844e9db..ad7f6e1 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -24,47 +24,6 @@
// Advanced I/O classes like sockets and process management are implemented
// using functions listed in io_natives.cc.
#define BUILTIN_NATIVE_LIST(V) \
- V(Crypto_GetRandomBytes, 1) \
- V(Directory_Exists, 1) \
- V(Directory_Create, 1) \
- V(Directory_Current, 0) \
- V(Directory_SetCurrent, 1) \
- V(Directory_SystemTemp, 0) \
- V(Directory_CreateTemp, 1) \
- V(Directory_Delete, 2) \
- V(Directory_Rename, 2) \
- V(Directory_List, 3) \
- V(File_Open, 2) \
- V(File_Exists, 1) \
- V(File_GetFD, 1) \
- V(File_Close, 1) \
- V(File_ReadByte, 1) \
- V(File_WriteByte, 2) \
- V(File_Read, 2) \
- V(File_ReadInto, 4) \
- V(File_WriteFrom, 4) \
- V(File_Position, 1) \
- V(File_SetPosition, 2) \
- V(File_Truncate, 2) \
- V(File_Length, 1) \
- V(File_LengthFromPath, 1) \
- V(File_Stat, 1) \
- V(File_LastModified, 1) \
- V(File_Flush, 1) \
- V(File_Lock, 4) \
- V(File_Create, 1) \
- V(File_CreateLink, 2) \
- V(File_LinkTarget, 1) \
- V(File_Delete, 1) \
- V(File_DeleteLink, 1) \
- V(File_Rename, 2) \
- V(File_Copy, 2) \
- V(File_RenameLink, 2) \
- V(File_ResolveSymbolicLinks, 1) \
- V(File_OpenStdio, 1) \
- V(File_GetStdioHandleType, 1) \
- V(File_GetType, 2) \
- V(File_AreIdentical, 2) \
V(Builtin_PrintString, 1) \
V(Builtin_LoadSource, 4) \
V(Builtin_AsyncLoadError, 3) \
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 11c5f5b4..dd63bec 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -482,12 +482,6 @@
Dart_Handle DartUtils::LoadScript(const char* script_uri,
Dart_Handle builtin_lib) {
Dart_Handle uri = Dart_NewStringFromCString(script_uri);
-
- Dart_Port load_port = Dart_ServiceWaitForLoadPort();
- if (load_port == ILLEGAL_PORT) {
- return NewDartUnsupportedError("Service did not return load port.");
- }
- Builtin::SetLoadPort(load_port);
IsolateData* isolate_data =
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
Dart_TimelineAsyncBegin("LoadScript", &(isolate_data->load_async_id));
@@ -632,11 +626,12 @@
}
-void DartUtils::PrepareBuiltinLibrary(Dart_Handle builtin_lib,
- Dart_Handle internal_lib,
- bool is_service_isolate,
- bool trace_loading,
- const char* package_root) {
+Dart_Handle DartUtils::PrepareBuiltinLibrary(Dart_Handle builtin_lib,
+ Dart_Handle internal_lib,
+ bool is_service_isolate,
+ bool trace_loading,
+ const char* package_root,
+ const char* packages_file) {
// Setup the internal library's 'internalPrint' function.
Dart_Handle print = Dart_Invoke(
builtin_lib, NewString("_getPrintClosure"), 0, NULL);
@@ -655,16 +650,20 @@
NewString("_traceLoading"), Dart_True());
DART_CHECK_VALID(result);
}
- }
-
- if (!is_service_isolate) {
// Set current working directory.
result = SetWorkingDirectory(builtin_lib);
DART_CHECK_VALID(result);
+ // Wait for the service isolate to initialize the load port.
+ Dart_Port load_port = Dart_ServiceWaitForLoadPort();
+ if (load_port == ILLEGAL_PORT) {
+ return NewDartUnsupportedError("Service did not return load port.");
+ }
+ Builtin::SetLoadPort(load_port);
}
// Set up package root if specified.
if (package_root != NULL) {
+ ASSERT(packages_file == NULL);
result = NewString(package_root);
DART_CHECK_VALID(result);
const int kNumArgs = 1;
@@ -675,7 +674,19 @@
kNumArgs,
dart_args);
DART_CHECK_VALID(result);
+ } else if (packages_file != NULL) {
+ result = NewString(packages_file);
+ DART_CHECK_VALID(result);
+ const int kNumArgs = 1;
+ Dart_Handle dart_args[kNumArgs];
+ dart_args[0] = result;
+ result = Dart_Invoke(builtin_lib,
+ NewString("_loadPackagesMap"),
+ kNumArgs,
+ dart_args);
+ DART_CHECK_VALID(result);
}
+ return Dart_True();
}
@@ -718,6 +729,7 @@
Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root,
+ const char* packages_file,
bool is_service_isolate,
bool trace_loading,
Dart_Handle builtin_lib) {
@@ -746,11 +758,14 @@
Dart_Handle result = Dart_FinalizeLoading(false);
DART_CHECK_VALID(result);
- PrepareBuiltinLibrary(builtin_lib,
- internal_lib,
- is_service_isolate,
- trace_loading,
- package_root);
+ result = PrepareBuiltinLibrary(builtin_lib,
+ internal_lib,
+ is_service_isolate,
+ trace_loading,
+ package_root,
+ packages_file);
+ DART_CHECK_VALID(result);
+
PrepareAsyncLibrary(async_lib, isolate_lib);
PrepareCoreLibrary(core_lib, builtin_lib, is_service_isolate);
PrepareIsolateLibrary(isolate_lib);
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 0c9ac19..8a9c953 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -124,11 +124,12 @@
Dart_Handle url);
static Dart_Handle LoadScript(const char* script_uri,
Dart_Handle builtin_lib);
- static void PrepareBuiltinLibrary(Dart_Handle builtin_lib,
- Dart_Handle internal_lib,
- bool is_service_isolate,
- bool trace_loading,
- const char* package_root);
+ static Dart_Handle PrepareBuiltinLibrary(Dart_Handle builtin_lib,
+ Dart_Handle internal_lib,
+ bool is_service_isolate,
+ bool trace_loading,
+ const char* package_root,
+ const char* packages_file);
static void PrepareCoreLibrary(Dart_Handle core_lib,
Dart_Handle builtin_lib,
bool is_service_isolate);
@@ -137,6 +138,7 @@
static void PrepareIOLibrary(Dart_Handle io_lib);
static void PrepareIsolateLibrary(Dart_Handle isolate_lib);
static Dart_Handle PrepareForScriptLoading(const char* package_root,
+ const char* packages_file,
bool is_service_isolate,
bool trace_loading,
Dart_Handle builtin_lib);
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 0b69d91..2f19fb2 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -592,6 +592,7 @@
// closures and setting up 'package root' for URI resolution.
result =
DartUtils::PrepareForScriptLoading(package_root,
+ NULL,
false,
false,
builtin_lib);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 8bbd2cd..2be3f34 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -20,7 +20,48 @@
// Some classes, like File and Directory, list their implementations in
// builtin_natives.cc instead.
#define IO_NATIVE_LIST(V) \
+ V(Crypto_GetRandomBytes, 1) \
+ V(Directory_Exists, 1) \
+ V(Directory_Create, 1) \
+ V(Directory_Current, 0) \
+ V(Directory_SetCurrent, 1) \
+ V(Directory_SystemTemp, 0) \
+ V(Directory_CreateTemp, 1) \
+ V(Directory_Delete, 2) \
+ V(Directory_Rename, 2) \
+ V(Directory_List, 3) \
V(EventHandler_SendData, 3) \
+ V(File_Open, 2) \
+ V(File_Exists, 1) \
+ V(File_GetFD, 1) \
+ V(File_Close, 1) \
+ V(File_ReadByte, 1) \
+ V(File_WriteByte, 2) \
+ V(File_Read, 2) \
+ V(File_ReadInto, 4) \
+ V(File_WriteFrom, 4) \
+ V(File_Position, 1) \
+ V(File_SetPosition, 2) \
+ V(File_Truncate, 2) \
+ V(File_Length, 1) \
+ V(File_LengthFromPath, 1) \
+ V(File_Stat, 1) \
+ V(File_LastModified, 1) \
+ V(File_Flush, 1) \
+ V(File_Lock, 4) \
+ V(File_Create, 1) \
+ V(File_CreateLink, 2) \
+ V(File_LinkTarget, 1) \
+ V(File_Delete, 1) \
+ V(File_DeleteLink, 1) \
+ V(File_Rename, 2) \
+ V(File_Copy, 2) \
+ V(File_RenameLink, 2) \
+ V(File_ResolveSymbolicLinks, 1) \
+ V(File_OpenStdio, 1) \
+ V(File_GetStdioHandleType, 1) \
+ V(File_GetType, 2) \
+ V(File_AreIdentical, 2) \
V(FileSystemWatcher_CloseWatcher, 1) \
V(FileSystemWatcher_GetSocketId, 2) \
V(FileSystemWatcher_InitWatcher, 0) \
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 179bde5..49a993f 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -6,6 +6,7 @@
#define BIN_ISOLATE_DATA_H_
#include "include/dart_api.h"
+#include "platform/assert.h"
#include "platform/globals.h"
@@ -20,23 +21,31 @@
// when the isolate shuts down.
class IsolateData {
public:
- explicit IsolateData(const char* url, const char* package_root)
+ explicit IsolateData(const char* url,
+ const char* package_root,
+ const char* packages_file)
: script_url(strdup(url)),
package_root(NULL),
+ packages_file(NULL),
udp_receive_buffer(NULL),
load_async_id(-1) {
if (package_root != NULL) {
+ ASSERT(packages_file == NULL);
this->package_root = strdup(package_root);
+ } else if (packages_file != NULL) {
+ this->packages_file = strdup(packages_file);
}
}
~IsolateData() {
free(script_url);
free(package_root);
+ free(packages_file);
free(udp_receive_buffer);
}
char* script_url;
char* package_root;
+ char* packages_file;
uint8_t* udp_receive_buffer;
int64_t load_async_id;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 5b14dff..5c36f41 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -60,11 +60,22 @@
// free'd.)
static const char* commandline_package_root = NULL;
+// Value of the --packages flag.
+// (This pointer points into an argv buffer and does not need to be
+// free'd.)
+static const char* commandline_packages_file = NULL;
+
// Global flag that is used to indicate that we want to compile all the
// dart functions and not run anything.
static bool has_compile_all = false;
+
+// Global flag that is used to indicate that we want to compile all the
+// dart functions before running main and not compile anything thereafter.
+static bool has_precompile = false;
+
+
// Global flag that is used to indicate that we want to trace resolution of
// URIs and the loading of libraries, parts and scripts.
static bool has_trace_loading = false;
@@ -169,6 +180,17 @@
}
+static bool ProcessPackagesOption(const char* arg,
+ CommandLineOptions* vm_options) {
+ ASSERT(arg != NULL);
+ if (*arg == '\0' || *arg == '-') {
+ return false;
+ }
+ commandline_packages_file = arg;
+ return true;
+}
+
+
static void* GetHashmapKeyFromString(char* key) {
return reinterpret_cast<void*>(key);
}
@@ -266,6 +288,19 @@
return true;
}
+
+static bool ProcessPrecompileOption(const char* arg,
+ CommandLineOptions* vm_options) {
+ ASSERT(arg != NULL);
+ if (*arg != '\0') {
+ return false;
+ }
+ has_precompile = true;
+ vm_options->AddArgument("--precompile");
+ return true;
+}
+
+
static bool ProcessDebugOption(const char* option_value,
CommandLineOptions* vm_options) {
ASSERT(option_value != NULL);
@@ -371,10 +406,12 @@
{ "--verbose", ProcessVerboseOption },
{ "-v", ProcessVerboseOption },
{ "--package-root=", ProcessPackageRootOption },
+ { "--packages=", ProcessPackagesOption },
{ "-D", ProcessEnvironmentOption },
// VM specific options to the standalone dart program.
{ "--break-at=", ProcessBreakpointOption },
{ "--compile_all", ProcessCompileAllOption },
+ { "--precompile", ProcessPrecompileOption },
{ "--debug", ProcessDebugOption },
{ "--snapshot=", ProcessGenScriptSnapshotOption },
{ "--enable-vm-service", ProcessEnableVmServiceOption },
@@ -489,6 +526,14 @@
i++;
}
+ // Verify consistency of arguments.
+ if ((commandline_package_root != NULL) &&
+ (commandline_packages_file != NULL)) {
+ Log::PrintErr("Specifying both a packages directory and a packages "
+ "file is invalid.");
+ return -1;
+ }
+
return 0;
}
@@ -561,11 +606,14 @@
static Dart_Isolate CreateIsolateAndSetupHelper(const char* script_uri,
const char* main,
const char* package_root,
+ const char* packages_file,
Dart_IsolateFlags* flags,
char** error,
int* exit_code) {
ASSERT(script_uri != NULL);
- IsolateData* isolate_data = new IsolateData(script_uri, package_root);
+ IsolateData* isolate_data = new IsolateData(script_uri,
+ package_root,
+ packages_file);
Dart_Isolate isolate = NULL;
isolate = Dart_CreateIsolate(script_uri,
@@ -597,7 +645,10 @@
*error = strdup(VmService::GetErrorMessage());
return NULL;
}
- if (has_compile_all) {
+ if (has_precompile) {
+ result = Dart_Precompile();
+ CHECK_RESULT(result);
+ } else if (has_compile_all) {
result = Dart_CompileAll();
CHECK_RESULT(result);
}
@@ -618,6 +669,7 @@
// Prepare for script loading by setting up the 'print' and 'timer'
// closures and setting up 'package root' for URI resolution.
result = DartUtils::PrepareForScriptLoading(package_root,
+ packages_file,
false,
has_trace_loading,
builtin_lib);
@@ -675,16 +727,17 @@
return NULL;
}
}
+ const char* packages_file = NULL;
if (package_root == NULL) {
if (parent_isolate_data != NULL) {
package_root = parent_isolate_data->package_root;
- } else {
- package_root = ".";
+ packages_file = parent_isolate_data->packages_file;
}
}
return CreateIsolateAndSetupHelper(script_uri,
main,
package_root,
+ packages_file,
flags,
error,
&exit_code);
@@ -712,6 +765,12 @@
" all VM options).\n"
"--package-root=<path> or -p<path>\n"
" Where to find packages, that is, \"package:...\" imports.\n"
+"--packages=<path>\n"
+" Where to find a package spec file.\n"
+"--observe[=<port>[/<bind-address>]]\n"
+" Enable the VM service and cause isolates to pause on exit (default port is\n"
+" 8181, default bind address is 127.0.0.1). With the default options,\n"
+" Observatory will be available locally at http://127.0.0.1:8181/\n"
"--version\n"
" Print the VM version.\n");
} else {
@@ -724,6 +783,12 @@
" all VM options).\n"
"--package-root=<path> or -p<path>\n"
" Where to find packages, that is, \"package:...\" imports.\n"
+"--packages=<path>\n"
+" Where to find a package spec file.\n"
+"--observe[=<port>[/<bind-address>]]\n"
+" Enable the VM service and cause isolates to pause on exit (default port is\n"
+" 8181, default bind address is 127.0.0.1). With the default options,\n"
+" Observatory will be available locally at http://127.0.0.1:8181/\n"
"--version\n"
" Print the VM version.\n"
"\n"
@@ -989,6 +1054,7 @@
Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
"main",
commandline_package_root,
+ commandline_packages_file,
NULL,
&error,
&exit_code);
@@ -1041,7 +1107,10 @@
ASSERT(!Dart_IsError(builtin_lib));
result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
- if (has_compile_all) {
+ if (has_precompile) {
+ result = Dart_Precompile();
+ DartExitOnError(result);
+ } else if (has_compile_all) {
result = Dart_CompileAll();
DartExitOnError(result);
}
diff --git a/runtime/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index a95df08..68f63d9 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.dart
@@ -4,10 +4,14 @@
part of vmservice_io;
+_log(msg) {
+ print("% $msg");
+}
+
var _httpClient;
// Send a response to the requesting isolate.
-void _sendResponse(SendPort sp, int id, dynamic data) {
+void _sendResourceResponse(SendPort sp, int id, dynamic data) {
assert((data is List<int>) || (data is String));
var msg = new List(2);
msg[0] = id;
@@ -29,17 +33,17 @@
if (response.statusCode != 200) {
var msg = "Failure getting $uri:\n"
" ${response.statusCode} ${response.reasonPhrase}";
- _sendResponse(sp, id, msg);
+ _sendResourceResponse(sp, id, msg);
} else {
- _sendResponse(sp, id, builder.takeBytes());
+ _sendResourceResponse(sp, id, builder.takeBytes());
}
},
onError: (e) {
- _sendResponse(sp, d, e.toString());
+ _sendResourceResponse(sp, id, e.toString());
});
})
.catchError((e) {
- _sendResponse(sp, id, e.toString());
+ _sendResourceResponse(sp, id, e.toString());
});
// It's just here to push an event on the event loop so that we invoke the
// scheduled microtasks.
@@ -50,11 +54,11 @@
var path = uri.toFilePath();
var sourceFile = new File(path);
sourceFile.readAsBytes().then((data) {
- _sendResponse(sp, id, data);
+ _sendResourceResponse(sp, id, data);
},
onError: (e) {
var err = "Error loading $uri:\n $e";
- _sendResponse(sp, id, err);
+ _sendResourceResponse(sp, id, err);
});
}
@@ -83,24 +87,365 @@
}
var data = UTF8.encode(Uri.decodeComponent(encodedData));
- _sendResponse(sp, id, data);
+ _sendResourceResponse(sp, id, data);
} catch (e) {
- _sendResponse(sp, id, "Invalid data uri ($uri):\n $e");
+ _sendResourceResponse(sp, id, "Invalid data uri ($uri):\n $e");
}
}
+_handleResourceRequest(SendPort sp, bool traceLoading, int id, Uri resource) {
+ if (resource.scheme == 'file') {
+ _loadFile(sp, id, resource);
+ } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) {
+ _loadHttp(sp, id, resource);
+ } else if ((resource.scheme == 'data')) {
+ _loadDataUri(sp, id, resource);
+ } else {
+ _sendResourceResponse(sp, id,
+ 'Unknown scheme (${resource.scheme}) for $resource');
+ }
+}
+
+
+// Handling of packages requests. Finding and parsing of .packages file or
+// packages/ directories.
+const _LF = 0x0A;
+const _CR = 0x0D;
+const _SPACE = 0x20;
+const _HASH = 0x23;
+const _DOT = 0x2E;
+const _COLON = 0x3A;
+const _DEL = 0x7F;
+
+const _invalidPackageNameChars = const [
+ // space ! " # $ % & '
+ true , false, true , true , false, true , false, false,
+ // ( ) * + , - . /
+ false, false, false, false, false, false, false, true ,
+ // 0 1 2 3 4 5 6 7
+ false, false, false, false, false, false, false, false,
+ // 8 9 : ; < = > ?
+ false, false, true , false, true , false, true , true ,
+ // @ A B C D E F G
+ false, false, false, false, false, false, false, false,
+ // H I J K L M N O
+ false, false, false, false, false, false, false, false,
+ // P Q R S T U V W
+ false, false, false, false, false, false, false, false,
+ // X Y Z [ \ ] ^ _
+ false, false, false, true , true , true , true , false,
+ // ` a b c d e f g
+ true , false, false, false, false, false, false, false,
+ // h i j k l m n o
+ false, false, false, false, false, false, false, false,
+ // p q r s t u v w
+ false, false, false, false, false, false, false, false,
+ // x y z { | } ~ DEL
+ false, false, false, true , true , true , false, true
+];
+
+_parsePackagesFile(SendPort sp,
+ bool traceLoading,
+ Uri packagesFile,
+ List<int> data) {
+ var result = [];
+ var index = 0;
+ var len = data.length;
+ while (index < len) {
+ var start = index;
+ var char = data[index];
+ if ((char == _CR) || (char == _LF)) {
+ // Skipping empty lines.
+ index++;
+ continue;
+ }
+
+ // Identify split within the line and end of the line.
+ var separator = -1;
+ var end = len;
+ // Verifying validity of package name while scanning the line.
+ var nonDot = false;
+ var invalidPackageName = false;
+
+ // Scan to the end of the line or data.
+ while (index < len) {
+ char = data[index++];
+ // If we have not reached the separator yet, determine whether we are
+ // scanning legal package name characters.
+ if (separator == -1) {
+ if ((char == _COLON)) {
+ // The first colon on a line is the separator between package name and
+ // related URI.
+ separator = index - 1;
+ } else {
+ // Still scanning the package name part. Check for the validity of
+ // the characters.
+ nonDot = nonDot || (char != _DOT);
+ invalidPackageName = invalidPackageName ||
+ (char < _SPACE) || (char > _DEL) ||
+ _invalidPackageNameChars[char - _SPACE];
+ }
+ }
+ // Identify end of line.
+ if ((char == _CR) || (char == _LF)) {
+ end = index - 1;
+ break;
+ }
+ }
+
+ // No further handling needed for comment lines.
+ if (data[start] == _HASH) {
+ if (traceLoading) {
+ _log("Skipping comment in $packagesFile:\n"
+ "${new String.fromCharCodes(data, start, end)}");
+ }
+ continue;
+ }
+
+ // Check for a badly formatted line, starting with a ':'.
+ if (separator == start) {
+ var line = new String.fromCharCodes(data, start, end);
+ if (traceLoading) {
+ _log("Line starts with ':' in $packagesFile:\n"
+ "$line");
+ }
+ sp.send("Missing package name in $packagesFile:\n"
+ "$line");
+ return;
+ }
+
+ // Ensure there is a separator on the line.
+ if (separator == -1) {
+ var line = new String.fromCharCodes(data, start, end);
+ if (traceLoading) {
+ _log("Line has no ':' in $packagesFile:\n"
+ "$line");
+ }
+ sp.send("Missing ':' separator in $packagesFile:\n"
+ "$line");
+ return;
+ }
+
+ var packageName = new String.fromCharCodes(data, start, separator);
+
+ // Check for valid package name.
+ if (invalidPackageName || !nonDot) {
+ var line = new String.fromCharCodes(data, start, end);
+ if (traceLoading) {
+ _log("Invalid package name $packageName in $packagesFile");
+ }
+ sp.send("Invalid package name '$packageName' in $packagesFile:\n"
+ "$line");
+ return;
+ }
+
+ if (traceLoading) {
+ _log("packageName: $packageName");
+ }
+ var packageUri = new String.fromCharCodes(data, separator + 1, end);
+ if (traceLoading) {
+ _log("original packageUri: $packageUri");
+ }
+ // Ensure the package uri ends with a /.
+ if (!packageUri.endsWith("/")) {
+ packageUri = "$packageUri/";
+ }
+ packageUri = packagesFile.resolve(packageUri).toString();
+ if (traceLoading) {
+ _log("mapping: $packageName -> $packageUri");
+ }
+ result.add(packageName);
+ result.add(packageUri);
+ }
+
+ if (traceLoading) {
+ _log("Parsed packages file at $packagesFile. Sending:\n$result");
+ }
+ sp.send(result);
+}
+
+_loadPackagesFile(SendPort sp, bool traceLoading, Uri packagesFile) async {
+ try {
+ var data = await new File.fromUri(packagesFile).readAsBytes();
+ if (traceLoading) {
+ _log("Loaded packages file from $packagesFile:\n"
+ "${new String.fromCharCodes(data)}");
+ }
+ _parsePackagesFile(sp, traceLoading, packagesFile, data);
+ } catch (e, s) {
+ if (traceLoading) {
+ _log("Error loading packages: $e\n$s");
+ }
+ sp.send("Uncaught error ($e) loading packags file.");
+ }
+}
+
+_findPackagesFile(SendPort sp, bool traceLoading, Uri base) async {
+ try {
+ // Walk up the directory hierarchy to check for the existence of
+ // .packages files in parent directories and for the existense of a
+ // packages/ directory on the first iteration.
+ var dir = new File.fromUri(base).parent;
+ var prev = null;
+ // Keep searching until we reach the root.
+ while ((prev == null) || (prev.path != dir.path)) {
+ // Check for the existence of a .packages file and if it exists try to
+ // load and parse it.
+ var dirUri = dir.uri;
+ var packagesFile = dirUri.resolve(".packages");
+ if (traceLoading) {
+ _log("Checking for $packagesFile file.");
+ }
+ var exists = await new File.fromUri(packagesFile).exists();
+ if (traceLoading) {
+ _log("$packagesFile exists: $exists");
+ }
+ if (exists) {
+ _loadPackagesFile(sp, traceLoading, packagesFile);
+ return;
+ }
+ // On the first loop try whether there is a packages/ directory instead.
+ if (prev == null) {
+ var packageRoot = dirUri.resolve("packages/");
+ if (traceLoading) {
+ _log("Checking for $packageRoot directory.");
+ }
+ exists = await new Directory.fromUri(packageRoot).exists();
+ if (traceLoading) {
+ _log("$packageRoot exists: $exists");
+ }
+ if (exists) {
+ if (traceLoading) {
+ _log("Found a package root at: $packageRoot");
+ }
+ sp.send([packageRoot.toString()]);
+ return;
+ }
+ }
+ // Move up one level.
+ prev = dir;
+ dir = dir.parent;
+ }
+
+ // No .packages file was found.
+ if (traceLoading) {
+ _log("Could not resolve a package location from $base");
+ }
+ sp.send("Could not resolve a package location for base at $base");
+ } catch (e, s) {
+ if (traceLoading) {
+ _log("Error loading packages: $e\n$s");
+ }
+ sp.send("Uncaught error ($e) loading packages file.");
+ }
+}
+
+
+Future<bool> _loadHttpPackagesFile(SendPort sp,
+ bool traceLoading,
+ Uri resource) async {
+ try {
+ if (_httpClient == null) {
+ _httpClient = new HttpClient()..maxConnectionsPerHost = 6;
+ }
+ if (traceLoading) {
+ _log("Fetching packages file from '$resource'.");
+ }
+ var req = await _httpClient.getUrl(resource);
+ var rsp = await req.close();
+ var builder = new BytesBuilder(copy: false);
+ await for (var bytes in rsp) {
+ builder.add(bytes);
+ }
+ if (rsp.statusCode != 200) {
+ if (traceLoading) {
+ _log("Got status ${rsp.statusCode} fetching '$resource'.");
+ }
+ return false;
+ }
+ var data = builder.takeBytes();
+ if (traceLoading) {
+ _log("Loaded packages file from '$resource':\n"
+ "${new String.fromCharCodes(data)}");
+ }
+ _parsePackagesFile(sp, traceLoading, resource, data);
+ } catch (e, s) {
+ if (traceLoading) {
+ _log("Error loading packages file from '$resource': $e\n$s");
+ }
+ sp.send("Uncaught error ($e) loading packages file from '$resource'.");
+ }
+ return false;
+}
+
+_handlePackagesRequest(SendPort sp,
+ bool traceLoading,
+ int id,
+ Uri resource) async {
+ try {
+ if (id == -1) {
+ if (resource.scheme == 'file') {
+ _findPackagesFile(sp, traceLoading, resource);
+ } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) {
+ // Try to load the .packages file next to the resource.
+ var packagesUri = resource.resolve(".packages");
+ var exists = await _loadHttpPackagesFile(sp, traceLoading, packagesUri);
+ if (!exists) {
+ // If the loading of the .packages file failed for http/https based
+ // scripts then setup the package root.
+ var packageRoot = resource.resolve('packages/');
+ sp.send([packageRoot.toString()]);
+ }
+ } else {
+ sp.send("Unsupported base URI to identify .packages file: "
+ "'$resource'.");
+ }
+ } else if (id == -2) {
+ if (traceLoading) {
+ _log("Handling load of packages map: '$resource'.");
+ }
+ if (resource.scheme == 'file') {
+ var exists = await new File.fromUri(resource).exists();
+ if (exists) {
+ _loadPackagesFile(sp, traceLoading, resource);
+ } else {
+ sp.send("Packages file '$resource' not found.");
+ }
+ } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) {
+ var exists = await _loadHttpPackagesFile(sp, traceLoading, resource);
+ if (!exists) {
+ sp.send("Packages file '$resource' not found.");
+ }
+ } else {
+ sp.send("Unknown scheme (${resource.scheme}) for package file at "
+ "'$resource'.");
+ }
+ } else {
+ sp.send("Unknown packages request id: $id for '$resource'.");
+ }
+ } catch (e, s) {
+ if (traceLoading) {
+ _log("Error handling packages request: $e\n$s");
+ }
+ sp.send("Uncaught error ($e) handling packages request.");
+ }
+}
+
+
+// External entry point for loader requests.
_processLoadRequest(request) {
SendPort sp = request[0];
- int id = request[1];
- String resource = request[2];
- var uri = Uri.parse(request[2]);
- if (uri.scheme == 'file') {
- _loadFile(sp, id, uri);
- } else if ((uri.scheme == 'http') || (uri.scheme == 'https')) {
- _loadHttp(sp, id, uri);
- } else if ((uri.scheme == 'data')) {
- _loadDataUri(sp, id, uri);
+ assert(sp != null);
+ bool traceLoading = request[1];
+ assert(traceLoading != null);
+ int id = request[2];
+ assert(id != null);
+ String resource = request[3];
+ assert(resource != null);
+ var uri = Uri.parse(resource);
+ if (id >= 0) {
+ _handleResourceRequest(sp, traceLoading, id, uri);
} else {
- sp.send([id, 'Unknown scheme (${uri.scheme}) for $uri']);
+ _handlePackagesRequest(sp, traceLoading, id, uri);
}
}
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 4723ca5..1f807e7 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -8,6 +8,7 @@
static const int PARSE_ERROR_CODE = 4000;
static const int BINARY_MESSAGE_ERROR_CODE = 4001;
static const int NOT_MAP_ERROR_CODE = 4002;
+ static const int ID_ERROR_CODE = 4003;
final WebSocket socket;
WebSocketClient(this.socket, VMService service) : super(service) {
@@ -29,6 +30,9 @@
return;
}
var serial = map['id'];
+ if (serial != null && serial is! num && serial is! String) {
+ socket.close(ID_ERROR_CODE, '"id" must be a number, string, or null.');
+ }
onMessage(serial, new Message.fromJsonRpc(this, map));
} else {
socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
@@ -91,21 +95,6 @@
_displayMessages = (_ip != '127.0.0.1' || _port != 8181);
}
- bool _shouldServeObservatory(HttpRequest request) {
- if (request.headers['Observatory-Version'] != null) {
- // Request is already coming from Observatory.
- return false;
- }
- // TODO(johnmccutchan): Test with obscure browsers.
- if (request.headers.value(HttpHeaders.USER_AGENT).contains('Mozilla')) {
- // Request is coming from a browser but not Observatory application.
- // Serve Observatory and let the Observatory make the real request.
- return true;
- }
- // All other user agents are assumed to be textual.
- return false;
- }
-
void _requestHandler(HttpRequest request) {
// Allow cross origin requests with 'observatory' header.
request.response.headers.add('Access-Control-Allow-Origin', '*');
@@ -129,10 +118,6 @@
}
var resource = Resource.resources[path];
- if (resource == null && _shouldServeObservatory(request)) {
- resource = Resource.resources[ROOT_REDIRECT_PATH];
- assert(resource != null);
- }
if (resource != null) {
// Serving up a static resource (e.g. .css, .html, .png).
request.response.headers.contentType =
@@ -141,6 +126,7 @@
request.response.close();
return;
}
+ // HTTP based service request.
var client = new HttpRequestClient(request, _service);
var message = new Message.fromUri(client, request.uri);
client.onMessage(null, message);
diff --git a/runtime/bin/vmservice_dartium.cc b/runtime/bin/vmservice_dartium.cc
index 25af328..195a6ce 100644
--- a/runtime/bin/vmservice_dartium.cc
+++ b/runtime/bin/vmservice_dartium.cc
@@ -64,7 +64,8 @@
// Prepare for script loading by setting up the 'print' and 'timer'
// closures and setting up 'package root' for URI resolution.
- result = DartUtils::PrepareForScriptLoading(NULL, true, false, builtin_lib);
+ result = DartUtils::PrepareForScriptLoading(
+ NULL, NULL, true, false, builtin_lib);
CHECK_RESULT(result);
ASSERT(Dart_IsServiceIsolate(isolate));
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index d59be63..89d802f 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -172,7 +172,8 @@
// Prepare for script loading by setting up the 'print' and 'timer'
// closures and setting up 'package root' for URI resolution.
- result = DartUtils::PrepareForScriptLoading(NULL, true, false, builtin_lib);
+ result = DartUtils::PrepareForScriptLoading(
+ NULL, NULL, true, false, builtin_lib);
SHUTDOWN_ON_ERROR(result);
// Load main script.
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
index 2176aad..5a27249 100644
--- a/runtime/include/dart_native_api.h
+++ b/runtime/include/dart_native_api.h
@@ -40,6 +40,7 @@
Dart_CObject_kTypedData,
Dart_CObject_kExternalTypedData,
Dart_CObject_kSendPort,
+ Dart_CObject_kCapability,
Dart_CObject_kUnsupported,
Dart_CObject_kNumberOfTypes
} Dart_CObject_Type;
@@ -62,6 +63,9 @@
Dart_Port origin_id;
} as_send_port;
struct {
+ int64_t id;
+ } as_capability;
+ struct {
intptr_t length;
struct _Dart_CObject** values;
} as_array;
@@ -155,5 +159,6 @@
* TODO(turnidge): Document.
*/
DART_EXPORT Dart_Handle Dart_CompileAll();
+DART_EXPORT Dart_Handle Dart_Precompile();
#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 0358cc2..2a45ae7 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -205,27 +205,3 @@
}
}
}
-
-patch class Resource {
- /* patch */ const factory Resource(String uri) = _Resource;
-}
-
-class _Resource implements Resource {
- final String _location;
-
- const _Resource(String uri) : _location = uri;
-
- Uri get uri => Uri.base.resolve(_location);
-
- Stream<List<int>> openRead() {
- throw new UnimplementedError("openRead");
- }
-
- Future<List<int>> readAsBytes() {
- throw new UnimplementedError("readAsBytes");
- }
-
- Future<String> readAsString({Encoding encoding}) {
- throw new UnimplementedError("readAsString");
- }
-}
diff --git a/runtime/lib/core_sources.gypi b/runtime/lib/core_sources.gypi
index 8bab528..73a4e04 100644
--- a/runtime/lib/core_sources.gypi
+++ b/runtime/lib/core_sources.gypi
@@ -44,6 +44,7 @@
'object_patch.dart',
'regexp.cc',
'regexp_patch.dart',
+ 'resource_patch.dart',
'stacktrace.cc',
'stacktrace.dart',
'stopwatch.cc',
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index 786e5de..464e89b 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -37,4 +37,26 @@
return inspectee.raw();
}
+
+DEFINE_NATIVE_ENTRY(Developer_log, 8) {
+ GET_NON_NULL_NATIVE_ARGUMENT(String, message, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Integer, timestamp, arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(Integer, sequence, arguments->NativeArgAt(2));
+ GET_NON_NULL_NATIVE_ARGUMENT(Smi, level, arguments->NativeArgAt(3));
+ GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(4));
+ GET_NATIVE_ARGUMENT(Instance, dart_zone, arguments->NativeArgAt(5));
+ GET_NATIVE_ARGUMENT(Instance, error, arguments->NativeArgAt(6));
+ GET_NATIVE_ARGUMENT(Instance, stack_trace, arguments->NativeArgAt(7));
+ Service::SendLogEvent(isolate,
+ sequence.AsInt64Value(),
+ timestamp.AsInt64Value(),
+ level.Value(),
+ name,
+ message,
+ dart_zone,
+ error,
+ stack_trace);
+ return Object::null();
+}
+
} // namespace dart
diff --git a/runtime/lib/developer.dart b/runtime/lib/developer.dart
index 689f23e..707d591 100644
--- a/runtime/lib/developer.dart
+++ b/runtime/lib/developer.dart
@@ -2,6 +2,50 @@
// 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.
-patch bool debugger({bool when: true, String msg}) native "Developer_debugger";
+patch bool debugger({bool when: true,
+ String message}) native "Developer_debugger";
-patch inspect(object) native "Developer_inspect";
+patch Object inspect(Object object) native "Developer_inspect";
+
+patch log(String message,
+ {DateTime time,
+ int sequenceNumber,
+ int level: 0,
+ String name: '',
+ Zone zone,
+ Object error,
+ StackTrace stackTrace}) {
+ if (message is! String) {
+ throw new ArgumentError(message, "message", "Must be a String");
+ }
+ if (time == null) {
+ time = new DateTime.now();
+ }
+ if (time is! DateTime) {
+ throw new ArgumentError(time, "time", "Must be a DateTime");
+ }
+ if (sequenceNumber == null) {
+ sequenceNumber = _nextSequenceNumber++;
+ } else {
+ _nextSequenceNumber = sequenceNumber + 1;
+ }
+ return _log(message,
+ time.millisecondsSinceEpoch,
+ sequenceNumber,
+ level,
+ name,
+ zone,
+ error,
+ stackTrace);
+}
+
+int _nextSequenceNumber = 0;
+
+_log(String message,
+ int timestamp,
+ int sequenceNumber,
+ int level,
+ String name,
+ Zone zone,
+ Object error,
+ StackTrace stackTrace) native "Developer_log";
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index 63f868b..9192b28 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -2,8 +2,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.
-// TODO(srdjan): fix limitations.
-// - shift amount must be a Smi.
class _IntegerImplementation extends _Num {
// The Dart class _Bigint extending _IntegerImplementation requires a
// default constructor.
diff --git a/runtime/lib/internal_patch.dart b/runtime/lib/internal_patch.dart
index ce44229..f2fe680 100644
--- a/runtime/lib/internal_patch.dart
+++ b/runtime/lib/internal_patch.dart
@@ -13,6 +13,8 @@
static var timerFactory;
// Example: "dart:io _EventHandler._sendData"
static var eventHandlerSendData;
+ // Implementation of Resource.readAsBytes.
+ static var resourceReadAsBytes;
}
patch class CodeUnits {
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 7e1c496..e3dbec1 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -301,7 +301,7 @@
readyPort.close();
}
return new Future<Isolate>.error(e, st);
- };
+ }
}
/* patch */ static Future<Isolate> spawnUri(
@@ -334,7 +334,7 @@
readyPort.close();
}
return new Future<Isolate>.error(e, st);
- };
+ }
return completer.future;
}
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index 45eb5ef..5942078 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -114,8 +114,6 @@
void _nextState() native "Random_nextState";
int nextInt(int max) {
- // TODO(srdjan): Remove the 'limit' check once optimizing comparison of
- // Smi-s with Mint constants.
final limit = 0x3FFFFFFF;
if (max <= 0 || ((max > limit) && (max > _POW2_32))) {
throw new ArgumentError("max must be positive and < 2^32:"
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 33af271..24c9523 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -373,10 +373,12 @@
static RawInstance* CreateLibraryMirror(const Library& lib) {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
ASSERT(!lib.IsNull());
- const Array& args = Array::Handle(Array::New(3));
- args.SetAt(0, MirrorReference::Handle(MirrorReference::New(lib)));
- String& str = String::Handle();
+ const Array& args = Array::Handle(zone, Array::New(3));
+ args.SetAt(0, MirrorReference::Handle(zone, MirrorReference::New(lib)));
+ String& str = String::Handle(zone);
str = lib.name();
args.SetAt(1, str);
str = lib.url();
@@ -384,6 +386,21 @@
// Censored library (grumble).
return Instance::null();
}
+ if (str.Equals("dart:io")) {
+ // Hack around dart:io being loaded into non-service isolates in Dartium.
+ Isolate* isolate = thread->isolate();
+ const GrowableObjectArray& libraries = GrowableObjectArray::Handle(
+ zone, isolate->object_store()->libraries());
+ Library& other_lib = Library::Handle(zone);
+ String& other_uri = String::Handle(zone);
+ for (intptr_t i = 0; i < libraries.Length(); i++) {
+ other_lib ^= libraries.At(i);
+ other_uri = other_lib.url();
+ if (other_uri.Equals("dart:html")) {
+ return Instance::null();
+ }
+ }
+ }
args.SetAt(2, str);
return CreateMirror(Symbols::_LocalLibraryMirror(), args);
}
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 2e55bfd..c64be5d 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -447,11 +447,16 @@
var result = reflect(_invokeGetter(_reflectee, unwrapped));
// Wait until success to avoid creating closures for non-existent getters,
// and defer the creation until the next getField invocation.
- _getFieldClosures[unwrapped] = (receiver) {
- var getterClosure = _createGetterClosure(unwrapped);
- _getFieldClosures[unwrapped] = getterClosure;
- return getterClosure(receiver);
- };
+ // o.<operator> is not valid Dart and will cause a compilation error, so
+ // don't attempt to generate such a closure.
+ bool isOperator = _LocalMethodMirror._operators.contains(unwrapped);
+ if (!isOperator) {
+ _getFieldClosures[unwrapped] = (receiver) {
+ var getterClosure = _createGetterClosure(unwrapped);
+ _getFieldClosures[unwrapped] = getterClosure;
+ return getterClosure(receiver);
+ };
+ }
return result;
}
diff --git a/runtime/lib/resource_patch.dart b/runtime/lib/resource_patch.dart
new file mode 100644
index 0000000..0643516
--- /dev/null
+++ b/runtime/lib/resource_patch.dart
@@ -0,0 +1,68 @@
+// 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.
+
+patch class Resource {
+ /* patch */ const factory Resource(String uri) = _Resource;
+}
+
+class _Resource implements Resource {
+ final String _location;
+
+ const _Resource(this._location);
+
+ Uri get uri => Uri.base.resolve(_location);
+
+ Stream<List<int>> openRead() {
+ if (VMLibraryHooks.resourceReadAsBytes == null) {
+ throw new UnimplementedError("openRead");
+ }
+
+ var controller = new StreamController<List<int>>();
+ // We only need to implement the listener as there is no way to provide
+ // back pressure into the channel.
+ controller.onListen = () {
+ // Once there is a listener, we kick off the loading of the resource.
+ readAsBytes().then((value) {
+ // The resource loading implementation sends all of the data in a
+ // single message. So the stream will only get a single value posted.
+ controller.add(value);
+ controller.close();
+ },
+ onError: (e, s) {
+ // In case the future terminates with an error we propagate it to the
+ // stream.
+ controller.addError(e, s);
+ controller.close();
+ });
+ };
+
+ return controller.stream;
+ }
+
+ Future<List<int>> readAsBytes() {
+ if (VMLibraryHooks.resourceReadAsBytes == null) {
+ throw new UnimplementedError("readAsBytes");
+ }
+
+ return VMLibraryHooks.resourceReadAsBytes(this.uri);
+ }
+
+ Future<String> readAsString({Encoding encoding : UTF8}) {
+ if (VMLibraryHooks.resourceReadAsBytes == null) {
+ throw new UnimplementedError("readAsString");
+ }
+
+ var completer = new Completer<String>();
+
+ readAsBytes().then((bytes) {
+ var str = encoding.decode(bytes);
+ completer.complete(str);
+ },
+ onError: (e, s) {
+ completer.completeError(e,s);
+ });
+
+ return completer.future;
+ }
+}
diff --git a/runtime/lib/string_buffer_patch.dart b/runtime/lib/string_buffer_patch.dart
index 6991ead..d087550 100644
--- a/runtime/lib/string_buffer_patch.dart
+++ b/runtime/lib/string_buffer_patch.dart
@@ -55,17 +55,7 @@
/* patch */ int get length => _partsCodeUnits + _bufferPosition;
/* patch */ void write(Object obj) {
- String str;
- if (obj is String) {
- str = obj;
- } else {
- // TODO(srdjan): The following four lines could be replaced by
- // '$obj', but apparently this is too slow on the Dart VM.
- str = obj.toString();
- if (str is! String) {
- throw new ArgumentError('toString() did not return a string');
- }
- }
+ String str = '$obj';
if (str.isEmpty) return;
_consumeBuffer();
_addPart(str);
diff --git a/runtime/lib/symbol_patch.dart b/runtime/lib/symbol_patch.dart
index 16a3ebb..fdb6527 100644
--- a/runtime/lib/symbol_patch.dart
+++ b/runtime/lib/symbol_patch.dart
@@ -11,6 +11,11 @@
static getUnmangledName(Symbol symbol) {
String string = Symbol.getName(symbol);
+ // Remove closurization hash mark
+ // #foo -> foo
+ if (string.startsWith('#')) {
+ string = string.substring(1);
+ }
// get:foo -> foo
// set:foo -> foo=
// get:_foo@xxx -> _foo
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index 5a25ea3..bcaf0ab 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -36,6 +36,7 @@
export 'package:observatory/src/elements/json_view.dart';
export 'package:observatory/src/elements/library_ref.dart';
export 'package:observatory/src/elements/library_view.dart';
+export 'package:observatory/src/elements/logging.dart';
export 'package:observatory/src/elements/metrics.dart';
export 'package:observatory/src/elements/nav_bar.dart';
export 'package:observatory/src/elements/object_common.dart';
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index c64656a..9888697 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -29,6 +29,7 @@
<link rel="import" href="src/elements/json_view.html">
<link rel="import" href="src/elements/library_ref.html">
<link rel="import" href="src/elements/library_view.html">
+<link rel="import" href="src/elements/logging.html">
<link rel="import" href="src/elements/metrics.html">
<link rel="import" href="src/elements/nav_bar.html">
<link rel="import" href="src/elements/object_common.html">
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index 0580f5c..0faa080 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -204,11 +204,11 @@
bytes.offsetInBytes + offset,
bytes.lengthInBytes - offset);
var map = _parseJSON(meta);
- if (map == null) {
+ if (map == null || map['method'] != 'streamNotify') {
return;
}
- var event = map['event'];
- var streamId = map['streamId'];
+ var event = map['params']['event'];
+ var streamId = map['params']['streamId'];
postServiceEvent(streamId, event, data);
});
}
@@ -218,9 +218,10 @@
if (map == null) {
return;
}
- var event = map['event'];
- if (event != null) {
- var streamId = map['streamId'];
+
+ if (map['method'] == 'streamNotify') {
+ var event = map['params']['event'];
+ var streamId = map['params']['streamId'];
postServiceEvent(streamId, event, null);
return;
}
diff --git a/runtime/observatory/lib/service_io.dart b/runtime/observatory/lib/service_io.dart
index 9bd5242..2a91426 100644
--- a/runtime/observatory/lib/service_io.dart
+++ b/runtime/observatory/lib/service_io.dart
@@ -16,7 +16,7 @@
class _IOWebSocket implements CommonWebSocket {
WebSocket _webSocket;
-
+
void connect(String address,
void onOpen(),
void onMessage(dynamic data),
@@ -34,20 +34,20 @@
onError();
});
}
-
+
bool get isOpen =>
(_webSocket != null) && (_webSocket.readyState == WebSocket.OPEN);
-
+
void send(dynamic data) {
_webSocket.add(data);
}
-
+
void close() {
if (_webSocket != null) {
_webSocket.close();
}
}
-
+
Future<ByteData> nonStringToByteData(dynamic data) {
assert(data is Uint8List);
Logger.root.info('Binary data size in bytes: ${data.lengthInBytes}');
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index 3dc046d..ff45043 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -138,6 +138,7 @@
_pageRegistry.add(new ErrorViewPage(this));
_pageRegistry.add(new MetricsPage(this));
_pageRegistry.add(new PortsPage(this));
+ _pageRegistry.add(new LoggingPage(this));
// Note that ErrorPage must be the last entry in the list as it is
// the catch all.
_pageRegistry.add(new ErrorPage(this));
@@ -225,4 +226,7 @@
Logger.root.warning('Caught exception: ${e}\n${st}');
notifications.add(new Notification.fromException(e, st));
}
+
+ // This map keeps track of which curly-blocks have been expanded by the user.
+ Map<String,bool> expansions = {};
}
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 3a96752..bc2bb43 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -294,6 +294,22 @@
}
}
+
+class LoggingPage extends SimplePage {
+ LoggingPage(app) : super('logging', 'logging-page', app);
+
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
+ if (element != null) {
+ /// Update the page.
+ LoggingPageElement page = element;
+ page.isolate = isolate;
+ }
+ });
+ }
+}
+
class ErrorViewPage extends Page {
ErrorViewPage(app) : super(app);
diff --git a/runtime/observatory/lib/src/cli/command.dart b/runtime/observatory/lib/src/cli/command.dart
index d6be00d..04ff48e 100644
--- a/runtime/observatory/lib/src/cli/command.dart
+++ b/runtime/observatory/lib/src/cli/command.dart
@@ -78,7 +78,7 @@
List<Command> _match(List<String> args, bool preferExact) {
if (args.isEmpty) {
return [];
- }
+ }
bool lastArg = (args.length == 1);
var matches = _matchLocal(args[0], !lastArg || preferExact);
if (matches.isEmpty) {
diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
index c29b30e..a67b1db 100644
--- a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
+++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
@@ -544,15 +544,6 @@
}
profileCodes.sort(_sortCodes);
- if (hasOptimizedCode()) {
- attributes.add('optimized');
- }
- if (hasUnoptimizedCode()) {
- attributes.add('unoptimized');
- }
- if (isInlined()) {
- attributes.add('inlined');
- }
_addKindBasedAttributes(attributes);
exclusiveTicks = int.parse(data['exclusiveTicks']);
inclusiveTicks = int.parse(data['inclusiveTicks']);
diff --git a/runtime/observatory/lib/src/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index cca7a1c..469609b 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -283,7 +283,7 @@
var base = match.group(1);
var qualifier = match.group(2);
base = (base == null ? '' : base);
-
+
if (qualifier == null) {
return _lookupClass(isolate, base, allowPrefix:true).then((classes) {
var completions = [];
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 7652a4b..bb5a626 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -432,12 +432,78 @@
}
}
-/// Displays a CpuProfile
-@CustomTag('cpu-profile')
-class CpuProfileElement extends ObservatoryElement {
- static const MICROSECONDS_PER_SECOND = 1000000.0;
+@CustomTag('sample-buffer-control')
+class SampleBufferControlElement extends ObservatoryElement {
+ SampleBufferControlElement.created() : super.created() {
+ _stopWatch.start();
+ }
- @published Isolate isolate;
+ Future<CpuProfile> reload(Isolate isolate) async {
+ profile.clear();
+ if (isolate == null) {
+ _update(profile);
+ // Notify listener.
+ onSampleBufferUpdate(profile);
+ return profile;
+ }
+ await _changeState(kFetchingState);
+ try {
+ var params = { 'tags': tagSelector };
+ var response = await isolate.invokeRpc('_getCpuProfile', params);
+ await _changeState(kLoadingState);
+ profile.load(isolate, response);
+ _update(profile);
+ await _changeState(kLoadedState);
+ // Notify listener.
+ onSampleBufferUpdate(profile);
+ return profile;
+ } catch (e, st) {
+ if (e is ServerRpcException) {
+ ServerRpcException se = e;
+ if (se.code == ServerRpcException.kFeatureDisabled) {
+ await _changeState(kDisabledState);
+ return profile;
+ }
+ }
+ await _changeState(kExceptionState, e, st);
+ rethrow;
+ }
+ }
+
+ Future _changeState(String newState, [exception, stackTrace]) {
+ if ((newState == kDisabledState) ||
+ (newState == kFetchingState) ||
+ (newState == kExceptionState)) {
+ loadTime = '';
+ fetchTime = '';
+ } else if (newState == kLoadingState) {
+ fetchTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds);
+ loadTime = '';
+ } else if (newState == kLoadedState) {
+ loadTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds);
+ }
+ state = newState;
+ this.exception = exception;
+ this.stackTrace = stackTrace;
+ _stopWatch.reset();
+ return window.animationFrame;
+ }
+
+ _update(CpuProfile sampleBuffer) {
+ sampleCount = profile.sampleCount.toString();
+ refreshTime = new DateTime.now().toString();
+ stackDepth = profile.stackDepth.toString();
+ sampleRate = profile.sampleRate.toStringAsFixed(0);
+ timeSpan = formatTime(profile.timeSpan);
+ }
+
+ void tagSelectorChanged(oldValue) {
+ reload(profile.isolate);
+ }
+
+ Function onSampleBufferUpdate;
+ @observable bool showTagSelector = true;
+
@observable String sampleCount = '';
@observable String refreshTime = '';
@observable String sampleRate = '';
@@ -446,119 +512,86 @@
@observable String fetchTime = '';
@observable String loadTime = '';
@observable String tagSelector = 'UserVM';
- @observable String modeSelector = 'Function';
- @observable String directionSelector = 'Up';
-
- @observable String state = 'Requested';
+ @observable String state = 'kFetching';
@observable var exception;
@observable var stackTrace;
- final Stopwatch _sw = new Stopwatch();
+ static const kDisabledState = 'kDisabled';
+ static const kExceptionState = 'Exception';
+ static const kFetchingState = 'kFetching';
+ static const kLoadedState = 'kLoaded';
+ static const kLoadingState = 'kLoading';
+
+ Isolate isolate;
final CpuProfile profile = new CpuProfile();
+ final Stopwatch _stopWatch = new Stopwatch();
+}
- CpuProfileElement.created() : super.created();
-
- @override
- void attached() {
- super.attached();
- }
-
- void isolateChanged(oldValue) {
- _getCpuProfile().catchError(app.handleException);
- }
-
- void tagSelectorChanged(oldValue) {
- _getCpuProfile().catchError(app.handleException);
- }
+@CustomTag('stack-trace-tree-config')
+class StackTraceTreeConfigElement extends ObservatoryElement {
+ StackTraceTreeConfigElement.created() : super.created();
void modeSelectorChanged(oldValue) {
- _updateView();
+ if (onTreeConfigChange == null) {
+ return;
+ }
+ onTreeConfigChange(modeSelector, directionSelector);
}
void directionSelectorChanged(oldValue) {
- _updateView();
- }
-
- Future clearCpuProfile() {
- profile.clear();
- if (isolate == null) {
- return new Future.value(null);
+ if (onTreeConfigChange == null) {
+ return;
}
- return isolate.invokeRpc('_clearCpuProfile', { })
- .then((ServiceMap response) {
- _updateView();
- });
+ onTreeConfigChange(modeSelector, directionSelector);
}
- Future refresh() {
- return _getCpuProfile();
+ Function onTreeConfigChange;
+ @observable bool showModeSelector = true;
+ @observable bool showDirectionSelector = true;
+ @observable String modeSelector = 'Function';
+ @observable String directionSelector = 'Up';
+}
+
+/// Displays a CpuProfile
+@CustomTag('cpu-profile')
+class CpuProfileElement extends ObservatoryElement {
+ CpuProfileElement.created() : super.created() {
+ _updateTask = new Task(update);
+ _renderTask = new Task(render);
}
- _onFetchStarted() {
- _sw.reset();
- _sw.start();
- state = 'Requested';
+ attached() {
+ super.attached();
+ sampleBufferControlElement =
+ shadowRoot.querySelector('#sampleBufferControl');
+ assert(sampleBufferControlElement != null);
+ sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange;
+ stackTraceTreeConfigElement =
+ shadowRoot.querySelector('#stackTraceTreeConfig');
+ assert(stackTraceTreeConfigElement != null);
+ stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
+ cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
+ assert(cpuProfileTreeElement != null);
+ cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
+ _updateTask.queue();
}
- _onFetchFinished() {
- _sw.stop();
- fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
+ isolateChanged(oldValue) {
+ _updateTask.queue();
}
- Future _onLoadStarted() {
- _sw.reset();
- _sw.start();
- state = 'Loading';
- return window.animationFrame;
- }
-
- _onLoadFinished() {
- _sw.stop();
- loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
- state = 'Loaded';
- }
-
- Future _getCpuProfile() async {
- profile.clear();
- if (isolate == null) {
- return new Future.value(null);
- }
- _onFetchStarted();
- try {
- var params = { 'tags': tagSelector };
- var response = await isolate.invokeRpc('_getCpuProfile', params);
- _onFetchFinished();
- await _onLoadStarted();
- profile.load(isolate, response);
- _onLoadFinished();
- _updateView();
- } catch (e, st) {
- bool handled = false;
- if (e is ServerRpcException) {
- ServerRpcException se = e;
- if (se.code == ServerRpcException.kFeatureDisabled) {
- state = 'Disabled';
- handled = true;
- }
- }
- if (!handled) {
- state = 'Exception';
- exception = e;
- stackTrace = st;
- rethrow;
- }
+ update() {
+ if (sampleBufferControlElement != null) {
+ sampleBufferControlElement.reload(isolate);
}
}
- void _updateView() {
- sampleCount = profile.sampleCount.toString();
- refreshTime = new DateTime.now().toString();
- stackDepth = profile.stackDepth.toString();
- sampleRate = profile.sampleRate.toStringAsFixed(0);
- timeSpan = formatTime(profile.timeSpan);
- CpuProfileTreeElement cpuProfileTreeElement =
- shadowRoot.querySelector('#cpuProfileTree');
+ onSampleBufferChange(CpuProfile sampleBuffer) {
+ _renderTask.queue();
+ }
+
+ onTreeConfigChange(String modeSelector, String directionSelector) {
ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
if (directionSelector != 'Up') {
direction = ProfileTreeDirection.Inclusive;
@@ -567,11 +600,33 @@
if (modeSelector == 'Code') {
mode = ProfileTreeMode.Code;
}
- cpuProfileTreeElement.profile = profile;
cpuProfileTreeElement.direction = direction;
cpuProfileTreeElement.mode = mode;
+ _renderTask.queue();
+ }
+
+ Future clearCpuProfile() async {
+ await isolate.invokeRpc('_clearCpuProfile', { });
+ _updateTask.queue();
+ return new Future.value(null);
+ }
+
+ Future refresh() {
+ _updateTask.queue();
+ return new Future.value(null);
+ }
+
+ render() {
cpuProfileTreeElement.render();
}
+
+ @published Isolate isolate;
+
+ Task _updateTask;
+ Task _renderTask;
+ SampleBufferControlElement sampleBufferControlElement;
+ StackTraceTreeConfigElement stackTraceTreeConfigElement;
+ CpuProfileTreeElement cpuProfileTreeElement;
}
class NameSortedTable extends SortedTable {
@@ -684,28 +739,9 @@
@CustomTag('cpu-profile-table')
class CpuProfileTableElement extends ObservatoryElement {
- final Stopwatch _sw = new Stopwatch();
- final CpuProfile profile = new CpuProfile();
- StreamSubscription _resizeSubscription;
- @observable NameSortedTable profileTable;
- @observable NameSortedTable profileCallersTable;
- @observable NameSortedTable profileCalleesTable;
- @observable ServiceFunction focusedFunction;
- @observable int focusedRow;
- @observable String fetchTime = '';
- @observable String loadTime = '';
- @observable String state = 'Requested';
- @observable var exception;
- @observable var stackTrace;
- @observable Isolate isolate;
- @observable String sampleCount = '';
- @observable String refreshTime = '';
- @observable String sampleRate = '';
- @observable String stackDepth = '';
- @observable String timeSpan = '';
- @observable String directionSelector = 'Up';
-
CpuProfileTableElement.created() : super.created() {
+ _updateTask = new Task(update);
+ _renderTask = new Task(render);
var columns = [
new SortedTableColumn.withFormatter('Executing (%)',
Utils.formatPercentNormalized),
@@ -735,6 +771,25 @@
attached() {
super.attached();
+ sampleBufferControlElement =
+ shadowRoot.querySelector('#sampleBufferControl');
+ assert(sampleBufferControlElement != null);
+ sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange;
+ // Disable the tag selector- we always want no tags.
+ sampleBufferControlElement.tagSelector = 'None';
+ sampleBufferControlElement.showTagSelector = false;
+ stackTraceTreeConfigElement =
+ shadowRoot.querySelector('#stackTraceTreeConfig');
+ assert(stackTraceTreeConfigElement != null);
+ stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
+ stackTraceTreeConfigElement.modeSelector = 'Function';
+ stackTraceTreeConfigElement.showModeSelector = false;
+ stackTraceTreeConfigElement.directionSelector = 'Down';
+ stackTraceTreeConfigElement.showDirectionSelector = false;
+ cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
+ assert(cpuProfileTreeElement != null);
+ cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
+ _updateTask.queue();
_resizeSubscription = window.onResize.listen((_) => _updateSize());
_updateSize();
}
@@ -755,10 +810,48 @@
e.style.setProperty('height', '${mainHeight}px');
}
- isolateChanged() {
- _getCpuProfile()
- .catchError(app.handleException)
- .whenComplete(checkParameters);
+ isolateChanged(oldValue) {
+ _updateTask.queue();
+ }
+
+ update() {
+ _clearView();
+ if (sampleBufferControlElement != null) {
+ sampleBufferControlElement.reload(isolate).whenComplete(checkParameters);
+ }
+ }
+
+ onSampleBufferChange(CpuProfile sampleBuffer) {
+ _renderTask.queue();
+ }
+
+ onTreeConfigChange(String modeSelector, String directionSelector) {
+ ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
+ if (directionSelector != 'Up') {
+ direction = ProfileTreeDirection.Inclusive;
+ }
+ ProfileTreeMode mode = ProfileTreeMode.Function;
+ if (modeSelector == 'Code') {
+ mode = ProfileTreeMode.Code;
+ }
+ cpuProfileTreeElement.direction = direction;
+ cpuProfileTreeElement.mode = mode;
+ _renderTask.queue();
+ }
+
+ Future clearCpuProfile() async {
+ await isolate.invokeRpc('_clearCpuProfile', { });
+ _updateTask.queue();
+ return new Future.value(null);
+ }
+
+ Future refresh() {
+ _updateTask.queue();
+ return new Future.value(null);
+ }
+
+ render() {
+ _updateView();
}
checkParameters() {
@@ -773,94 +866,12 @@
isolate.getObject(functionId).then((func) => _focusOnFunction(func));
}
- void directionSelectorChanged(oldValue) {
- _updateFunctionTreeView();
- }
-
- Future refresh() {
- return _getCpuProfile();
- }
-
- _onFetchStarted() {
- _sw.reset();
- _sw.start();
- state = 'Requested';
- }
-
- _onFetchFinished() {
- _sw.stop();
- fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
- }
-
- _onLoadStarted() {
- _sw.reset();
- _sw.start();
- state = 'Loading';
- }
-
- _onLoadFinished() {
- _sw.stop();
- loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
- state = 'Loaded';
- }
-
- Future clearCpuProfile() {
- profile.clear();
- _clearView();
- if (isolate == null) {
- return new Future.value(null);
- }
- return isolate.invokeRpc('_clearCpuProfile', { })
- .then((ServiceMap response) {
- _updateView();
- });
- }
-
- Future _getCpuProfile() async {
- profile.clear();
- _clearView();
- if (isolate == null) {
- return new Future.value(null);
- }
- _onFetchStarted();
- try {
- var params = { 'tags': 'None' };
- var response = await isolate.invokeRpc('_getCpuProfile', params);
- _onFetchFinished();
- _onLoadStarted();
- profile.load(isolate, response);
- profile.buildFunctionCallerAndCallees();
- _onLoadFinished();
- _updateView();
- } catch (e, st) {
- bool handled = false;
- if (e is ServerRpcException) {
- ServerRpcException se = e;
- if (se.code == ServerRpcException.kFeatureDisabled) {
- state = 'Disabled';
- handled = true;
- }
- }
- if (!handled) {
- state = 'Exception';
- exception = e;
- stackTrace = st;
- rethrow;
- }
- }
- }
-
_clearView() {
profileTable.clearRows();
_renderTable();
}
_updateView() {
- sampleCount = profile.sampleCount.toString();
- refreshTime = new DateTime.now().toString();
- stackDepth = profile.stackDepth.toString();
- sampleRate = profile.sampleRate.toStringAsFixed(0);
- timeSpan = formatTime(profile.timeSpan);
_buildFunctionTable();
_renderTable();
_updateFunctionTreeView();
@@ -1060,21 +1071,28 @@
///
TableTree functionTree;
_updateFunctionTreeView() {
- CpuProfileTreeElement cpuProfileTreeElement =
- shadowRoot.querySelector('#cpuProfileTree');
- ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
- if (directionSelector != 'Up') {
- direction = ProfileTreeDirection.Inclusive;
- }
- ProfileTreeMode mode = ProfileTreeMode.Function;
- cpuProfileTreeElement.profile = profile;
- cpuProfileTreeElement.direction = direction;
- cpuProfileTreeElement.mode = mode;
cpuProfileTreeElement.functionFilter = (FunctionCallTreeNode node) {
return node.profileFunction.function == focusedFunction;
};
cpuProfileTreeElement.render();
}
+
+ @published Isolate isolate;
+ @observable NameSortedTable profileTable;
+ @observable NameSortedTable profileCallersTable;
+ @observable NameSortedTable profileCalleesTable;
+ @observable ServiceFunction focusedFunction;
+ @observable int focusedRow;
+
+
+ StreamSubscription _resizeSubscription;
+ Task _updateTask;
+ Task _renderTask;
+
+ CpuProfile get profile => sampleBufferControlElement.profile;
+ SampleBufferControlElement sampleBufferControlElement;
+ StackTraceTreeConfigElement stackTraceTreeConfigElement;
+ CpuProfileTreeElement cpuProfileTreeElement;
}
enum ProfileTreeDirection {
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index 891783f..588f869 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -6,6 +6,161 @@
<link rel="import" href="sliding_checkbox.html">
<link rel="import" href="view_footer.html">
+<polymer-element name="sample-buffer-control" extends="observatory-element">
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .statusMessage {
+ font-size: 150%;
+ font-weight: bold;
+ }
+
+ .statusBox {
+ height: 100%;
+ padding: 1em;
+ }
+
+ .center {
+ align-items: center;
+ justify-content: center;
+ }
+
+ .notice {
+ background-color: #fcf8e3;
+ }
+
+ .red {
+ background-color: #f2dede;
+ }
+ </style>
+ <div class="content-centered-big">
+ <h2>Sample buffer</h2>
+ <hr>
+ <template if="{{ state == 'kFetching' }}">
+ <div class="statusBox shadow center">
+ <div class="statusMessage">Fetching profile from VM...</div>
+ </div>
+ </template>
+ <template if="{{ state == 'kLoading' }}">
+ <div class="statusBox shadow center">
+ <div class="statusMessage">Loading profile...</div>
+ </div>
+ </template>
+ <template if="{{ state == 'kDisabled' }}">
+ <div class="statusBox shadow center">
+ <div>
+ <h1>Profiling is disabled</h1>
+ <br>
+ Perhaps the <b>profile</b> flag has been disabled for this VM.
+ <br><br>
+ See all
+ <a on-click="{{ goto }}" _href="{{ gotoLink('/flags') }}">vm flags</a>
+ </div>
+ </div>
+ </template>
+ <template if="{{ state == 'kException' }}">
+ <div class="statusBox shadow center">
+ <div class="statusMessage">
+ <h1>Profiling is disabled due to unexpected exception:</h1>
+ <br>
+ <pre>{{ exception.toString() }}</pre>
+ <br>
+ <h1>Stack trace:</h1>
+ <br>
+ <pre>{{ stackTrace.toString() }}</pre>
+ </div>
+ </div>
+ </template>
+ <template if="{{ state == 'kLoaded' }}">
+ <div class="memberList">
+ <div class="memberItem">
+ <div class="memberName">Refreshed at </div>
+ <div class="memberValue">{{ refreshTime }} (fetched in {{ fetchTime }}) (loaded in {{ loadTime }})</div>
+ </div>
+ <div class="memberItem">
+ <div class="memberName">Profile contains</div>
+ <div class="memberValue">{{ sampleCount }} samples (spanning {{ timeSpan }})</div>
+ </div>
+ <div class="memberItem">
+ <div class="memberName">Sampling</div>
+ <div class="memberValue">{{ stackDepth }} stack frames @ {{ sampleRate }} Hz</div>
+ </div>
+ <template if="{{ showTagSelector }}">
+ <div class="memberItem">
+ <div class="memberName">Tag Order</div>
+ <div class="memberValue">
+ <select value="{{tagSelector}}">
+ <option value="UserVM">User > VM</option>
+ <option value="UserOnly">User</option>
+ <option value="VMUser">VM > User</option>
+ <option value="VMOnly">VM</option>
+ <option value="None">None</option>
+ </select>
+ </div>
+ </div>
+ </template>
+ </div>
+ </template>
+ </div>
+ </template>
+</polymer-element>
+
+<polymer-element name="stack-trace-tree-config" extends="observatory-element">
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .statusBox {
+ height: 100%;
+ padding: 1em;
+ }
+ </style>
+ <div class="content-centered-big">
+ <h2>Tree display</h2>
+ <hr>
+ <div class="memberList">
+ <template if="{{ showModeSelector }}">
+ <div class="memberItem">
+ <div class="memberName">Mode</div>
+ <div class="memberValue">
+ <select value="{{modeSelector}}">
+ <option value="Code">Code</option>
+ <option value="Function">Function</option>
+ </select>
+ </div>
+ </div>
+ </template>
+ <template if="{{ showDirectionSelector }}">
+ <div class="memberItem">
+ <div class="memberName">Call Tree Direction</div>
+ <div class="memberValue">
+ <select value="{{directionSelector}}">
+ <option value="Down">Top down</option>
+ <option value="Up">Bottom up</option>
+ </select>
+ </div>
+ </div>
+ </template>
+ </div>
+ <template if="{{ directionSelector == 'Down' }}">
+ <br>
+ <div class="statusBox shadow">
+ <div>Tree is rooted at main.</div>
+ <br>
+ <div>Child nodes are callees.</div>
+ </div>
+ </template>
+ <template if="{{ directionSelector == 'Up' }}">
+ <br>
+ <div class="statusBox shadow">
+ <div>Tree is rooted at executing function / code.</div>
+ <br>
+ <div>Child nodes are callers.</div>
+ </div>
+ </template>
+ </div>
+ </template>
+</polymer-element>
+
<polymer-element name="cpu-profile-tree" extends="observatory-element">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -211,68 +366,8 @@
}
</style>
- <div class="content-centered-big">
- <template if="{{ state == 'Requested' }}">
- <div class="statusBox shadow center">
- <div class="statusMessage">Fetching profile from VM...</div>
- </div>
- </template>
- <template if="{{ state == 'Loading' }}">
- <div class="statusBox shadow center">
- <div class="statusMessage">Loading profile...</div>
- </div>
- </template>
- <template if="{{ state == 'Disabled' }}">
- <div class="statusBox shadow center">
- <div>
- <h1>Profiling is disabled</h1>
- <br>
- Perhaps the <b>profile</b> flag has been disabled for this VM.
- <br><br>
- See all
- <a on-click="{{ goto }}" _href="{{ gotoLink('/flags') }}">vm flags</a>
- </div>
- </div>
- </template>
- <template if="{{ state == 'Exception' }}">
- <div class="statusBox shadow center">
- <div class="statusMessage">
- <h1>Profiling is disabled due to unexpected exception:</h1>
- <br>
- <pre>{{ exception.toString() }}</pre>
- <br>
- <h1>Stack trace:</h1>
- <br>
- <pre>{{ stackTrace.toString() }}</pre>
- </div>
- </div>
- </template>
- <template if="{{ state == 'Loaded' }}">
- <div class="memberList">
- <div class="memberItem">
- <div class="memberName">Refreshed at </div>
- <div class="memberValue">{{ refreshTime }} (fetched in {{ fetchTime }}) (loaded in {{ loadTime }})</div>
- </div>
- <div class="memberItem">
- <div class="memberName">Profile contains</div>
- <div class="memberValue">{{ sampleCount }} samples (spanning {{ timeSpan }})</div>
- </div>
- <div class="memberItem">
- <div class="memberName">Sampling</div>
- <div class="memberValue">{{ stackDepth }} stack frames @ {{ sampleRate }} Hz</div>
- </div>
- <div class="memberItem">
- <div class="memberName">Call Tree Direction</div>
- <div class="memberValue">
- <select value="{{directionSelector}}">
- <option value="Down">Top down</option>
- <option value="Up">Bottom up</option>
- </select>
- </div>
- </div>
- </div>
- </template>
- </div>
+ <sample-buffer-control id="sampleBufferControl"></sample-buffer-control>
+ <br>
<hr>
<div id="main" class="flex-row centered">
<div class="flex-item-45-percent full-height outlined scroll">
@@ -329,16 +424,21 @@
</div>
</div>
<br>
+ <stack-trace-tree-config id="stackTraceTreeConfig"></stack-trace-tree-config>
<br>
- <div class="focused-function-label">
- <template if="{{ focusedFunction != null }}">
- <span>Filtered tree: </span>
- <function-ref ref="{{ focusedFunction }}"></function-ref>
- </template>
- <template if="{{ focusedFunction == null }}">
- <span>No focused function</span>
- </template>
+ <div class="content-centered-big">
+ <div class="focused-function-label">
+ <template if="{{ focusedFunction != null }}">
+ <span>Filtered tree: </span>
+ <function-ref ref="{{ focusedFunction }}"></function-ref>
+ </template>
+ <template if="{{ focusedFunction == null }}">
+ <span>No focused function</span>
+ </template>
+ </div>
</div>
+ <br>
+ <br>
<div class="flex-row centered">
<div class="flex-item-90-percent outlined" style="margin: 16px; margin-left: 8px; margin-right: 8px">
<cpu-profile-tree id="cpuProfileTree"></cpu-profile-tree>
@@ -363,137 +463,12 @@
background-color: #ECECEC;
padding: 0.2em;
}
- .statusMessage {
- font-size: 150%;
- font-weight: bold;
- }
-
- .statusBox {
- height: 100%;
- padding: 1em;
- }
-
- .center {
- align-items: center;
- justify-content: center;
- }
-
- .notice {
- background-color: #fcf8e3;
- }
-
- .red {
- background-color: #f2dede;
- }
-
</style>
+ <sample-buffer-control id="sampleBufferControl"></sample-buffer-control>
+ <br>
+ <stack-trace-tree-config id="stackTraceTreeConfig"></stack-trace-tree-config>
+ <br>
<div class="content-centered-big">
- <h1>Sampled CPU profile</h1>
- <hr>
- <template if="{{ state == 'Requested' }}">
- <div class="statusBox shadow center">
- <div class="statusMessage">Fetching profile from VM...</div>
- </div>
- </template>
- <template if="{{ state == 'Loading' }}">
- <div class="statusBox shadow center">
- <div class="statusMessage">Loading profile...</div>
- </div>
- </template>
- <template if="{{ state == 'Disabled' }}">
- <div class="statusBox shadow center">
- <div>
- <h1>Profiling is disabled</h1>
- <br>
- Perhaps the <b>profile</b> flag has been disabled for this VM.
- <br><br>
- See all
- <a on-click="{{ goto }}" _href="{{ gotoLink('/flags') }}">vm flags</a>
- </div>
- </div>
- </template>
- <template if="{{ state == 'Exception' }}">
- <div class="statusBox shadow center">
- <div class="statusMessage">
- <h1>Profiling is disabled due to unexpected exception:</h1>
- <br>
- <pre>{{ exception.toString() }}</pre>
- <br>
- <h1>Stack trace:</h1>
- <br>
- <pre>{{ stackTrace.toString() }}</pre>
- </div>
- </div>
- </template>
- <template if="{{ state == 'Loaded' }}">
- <div class="memberList">
- <div class="memberItem">
- <div class="memberName">Refreshed at </div>
- <div class="memberValue">{{ refreshTime }} (fetched in {{ fetchTime }}) (loaded in {{ loadTime }})</div>
- </div>
- <div class="memberItem">
- <div class="memberName">Profile contains</div>
- <div class="memberValue">{{ sampleCount }} samples (spanning {{ timeSpan }})</div>
- </div>
- <div class="memberItem">
- <div class="memberName">Sampling</div>
- <div class="memberValue">{{ stackDepth }} stack frames @ {{ sampleRate }} Hz</div>
- </div>
- <div class="memberItem">
- <div class="memberName">Mode</div>
- <div class="memberValue">
- <select value="{{modeSelector}}">
- <option value="Code">Code</option>
- <option value="Function">Function</option>
- </select>
- </div>
- </div>
- <div class="memberItem">
- <div class="memberName">Tag Order</div>
- <div class="memberValue">
- <select value="{{tagSelector}}">
- <option value="UserVM">User > VM</option>
- <option value="UserOnly">User</option>
- <option value="VMUser">VM > User</option>
- <option value="VMOnly">VM</option>
- <option value="None">None</option>
- </select>
- </div>
- </div>
- <!--- Experimental
- <div class="memberItem">
- <div class="memberName">Call Tree Direction</div>
- <div class="memberValue">
- <select value="{{directionSelector}}">
- <option value="Down">Top down</option>
- <option value="Up">Bottom up</option>
- </select>
- </div>
- </div>
- --->
- </div>
- </template>
- <template if="{{ state == 'Loaded' && directionSelector == 'Down' }}">
- <br>
- <div class="statusBox shadow">
- <div>Tree is rooted at main.</div>
- <br>
- <div>Child nodes are callees.</div>
- <br>
- <div class="notice">To get the most out of this mode you may need to launch Dart with a higher --profile-depth flag value.</div>
- <div class="notice">Try 16, 32, ... up to 256 until [Truncated] approaches zero.</div>
- <div class="red">NOTE: Higher values will impact performance</div>
- </div>
- </template>
- <template if="{{ state == 'Loaded' && directionSelector == 'Up' }}">
- <br>
- <div class="statusBox shadow">
- <div>Tree is rooted at executing function / code.</div>
- <br>
- <div>Child nodes are callers.</div>
- </div>
- </template>
- <br><br>
<div class="tableWell shadow">
<cpu-profile-tree id="cpuProfileTree"></cpu-profile-tree>
</div>
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index e7dab1c..3442d98 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -111,6 +111,16 @@
border-bottom-left-radius:4px;
}
+.full {
+ height: 100%;
+ width: 100;
+}
+
+.flex-row {
+ display: flex;
+ flex-direction: row;
+}
+
/* Flex row container */
.flex-row {
display: flex;
diff --git a/runtime/observatory/lib/src/elements/curly_block.dart b/runtime/observatory/lib/src/elements/curly_block.dart
index 2632f3e..004a02e 100644
--- a/runtime/observatory/lib/src/elements/curly_block.dart
+++ b/runtime/observatory/lib/src/elements/curly_block.dart
@@ -5,36 +5,51 @@
library curly_block_element;
import 'package:polymer/polymer.dart';
+import 'observatory_element.dart';
@CustomTag('curly-block')
-class CurlyBlockElement extends PolymerElement {
+class CurlyBlockElement extends ObservatoryElement {
CurlyBlockElement.created() : super.created();
@observable bool expanded = false;
@observable bool busy = false;
@published var callback = null;
@published bool expand = false;
+ @published String expandKey;
void expandChanged(oldValue) {
expanded = expand;
}
+ void expandKeyChanged(oldValue) {
+ if (expandKey != null) {
+ var value = app.expansions[expandKey];
+ if (value != null) {
+ if (expanded != value) {
+ toggleExpand(null, null, null);
+ }
+ }
+ }
+ }
+
void doneCallback() {
expanded = !expanded;
+ if (expandKey != null) {
+ app.expansions[expandKey] = expanded;
+ }
busy = false;
}
void toggleExpand(var event, var b, var c) {
assert(callback == null || expand == false);
- event.stopPropagation();
if (busy) {
return;
}
+ busy = true;
if (callback != null) {
- busy = true;
callback(!expanded, doneCallback);
} else {
- expanded = !expanded;
+ doneCallback();
}
}
}
diff --git a/runtime/observatory/lib/src/elements/curly_block.html b/runtime/observatory/lib/src/elements/curly_block.html
index 1576020..d1702a2 100644
--- a/runtime/observatory/lib/src/elements/curly_block.html
+++ b/runtime/observatory/lib/src/elements/curly_block.html
@@ -1,6 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="observatory_element.html">
-<polymer-element name="curly-block">
+<polymer-element name="curly-block" extends="observatory-element">
<template>
<style>
.idle {
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 70a3208..ae0ab6f 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -10,6 +10,7 @@
import 'package:observatory/cli.dart';
import 'package:observatory/debugger.dart';
import 'package:observatory/service.dart';
+import 'package:logging/logging.dart';
import 'package:polymer/polymer.dart';
// TODO(turnidge): Move Debugger, DebuggerCommand to debugger library.
@@ -349,6 +350,75 @@
'Syntax: step\n';
}
+class LogCommand extends DebuggerCommand {
+ LogCommand(Debugger debugger) : super(debugger, 'log', []);
+
+ Future run(List<String> args) async {
+ if (args.length == 0) {
+ debugger.console.print(
+ 'Current log level: '
+ '${debugger._consolePrinter._minimumLogLevel.name}');
+ return new Future.value(null);
+ }
+ if (args.length > 1) {
+ debugger.console.print("log expects zero or one arguments");
+ return new Future.value(null);
+ }
+ var level = _findLevel(args[0]);
+ if (level == null) {
+ debugger.console.print('No such log level: ${args[0]}');
+ return new Future.value(null);
+ }
+ debugger._consolePrinter._minimumLogLevel = level;
+ debugger.console.print('Set log level to: ${level.name}');
+ return new Future.value(null);
+ }
+
+ Level _findLevel(String levelName) {
+ levelName = levelName.toUpperCase();
+ for (var level in Level.LEVELS) {
+ if (level.name == levelName) {
+ return level;
+ }
+ }
+ return null;
+ }
+
+ Future<List<String>> complete(List<String> args) {
+ if (args.length != 1) {
+ return new Future.value([args.join('')]);
+ }
+ var prefix = args[0].toUpperCase();
+ var result = <String>[];
+ for (var level in Level.LEVELS) {
+ if (level.name.startsWith(prefix)) {
+ result.add(level.name);
+ }
+ }
+ return new Future.value(result);
+ }
+
+ String helpShort =
+ 'Control which log messages are displayed';
+
+ String helpLong =
+ 'Get or set the minimum log level that should be displayed.\n'
+ '\n'
+ 'Log levels (in ascending order): ALL, FINEST, FINER, FINE, CONFIG, '
+ 'INFO, WARNING, SEVERE, SHOUT, OFF\n'
+ '\n'
+ 'Default: OFF\n'
+ '\n'
+ 'Syntax: log '
+ '# Display the current minimum log level.\n'
+ ' log <level> '
+ '# Set the minimum log level to <level>.\n'
+ ' log OFF '
+ '# Display no log messages.\n'
+ ' log ALL '
+ '# Display all log messages.\n';
+}
+
class AsyncNextCommand extends DebuggerCommand {
AsyncNextCommand(Debugger debugger) : super(debugger, 'anext', []) {
}
@@ -358,11 +428,9 @@
var event = debugger.isolate.pauseEvent;
if (event.asyncContinuation == null) {
debugger.console.print("No async continuation at this location");
- return;
+ } else {
+ return debugger.isolate.asyncStepOver()[Isolate.kFirstResume];
}
- var bpt = await
- debugger.isolate.addBreakOnActivation(event.asyncContinuation);
- return debugger.isolate.resume();
} else {
debugger.console.print('The program is already running');
}
@@ -486,25 +554,25 @@
'Add a breakpoint by source location or function name.\n'
'\n'
'Syntax: break '
- '- Break at the current position\n'
+ '# Break at the current position\n'
' break <line> '
- '- Break at a line in the current script\n'
+ '# Break at a line in the current script\n'
' '
' (e.g \'break 11\')\n'
' break <line>:<col> '
- '- Break at a line:col in the current script\n'
+ '# Break at a line:col in the current script\n'
' '
' (e.g \'break 11:8\')\n'
' break <script>:<line> '
- '- Break at a line:col in a specific script\n'
+ '# Break at a line:col in a specific script\n'
' '
' (e.g \'break test.dart:11\')\n'
' break <script>:<line>:<col> '
- '- Break at a line:col in a specific script\n'
+ '# Break at a line:col in a specific script\n'
' '
' (e.g \'break test.dart:11:8\')\n'
' break <function> '
- '- Break at the named function\n'
+ '# Break at the named function\n'
' '
' (e.g \'break main\' or \'break Class.someFunction\')\n';
}
@@ -569,25 +637,25 @@
'Remove a breakpoint by source location or function name.\n'
'\n'
'Syntax: clear '
- '- Clear at the current position\n'
+ '# Clear at the current position\n'
' clear <line> '
- '- Clear at a line in the current script\n'
+ '# Clear at a line in the current script\n'
' '
' (e.g \'clear 11\')\n'
' clear <line>:<col> '
- '- Clear at a line:col in the current script\n'
+ '# Clear at a line:col in the current script\n'
' '
' (e.g \'clear 11:8\')\n'
' clear <script>:<line> '
- '- Clear at a line:col in a specific script\n'
+ '# Clear at a line:col in a specific script\n'
' '
' (e.g \'clear test.dart:11\')\n'
' clear <script>:<line>:<col> '
- '- Clear at a line:col in a specific script\n'
+ '# Clear at a line:col in a specific script\n'
' '
' (e.g \'clear test.dart:11:8\')\n'
' clear <function> '
- '- Clear at the named function\n'
+ '# Clear at the named function\n'
' '
' (e.g \'clear main\' or \'clear Class.someFunction\')\n';
}
@@ -883,17 +951,23 @@
'Syntax: refresh <subcommand>\n';
}
-class _VMStreamPrinter {
+class _ConsoleStreamPrinter {
ObservatoryDebugger _debugger;
- _VMStreamPrinter(this._debugger);
-
+ _ConsoleStreamPrinter(this._debugger);
+ Level _minimumLogLevel = Level.OFF;
String _savedStream;
String _savedIsolate;
String _savedLine;
List<String> _buffer = [];
void onEvent(String streamName, ServiceEvent event) {
+ if (event.kind == ServiceEvent.kLogging) {
+ // Check if we should print this log message.
+ if (event.logRecord['level'].value < _minimumLogLevel.value) {
+ return;
+ }
+ }
String isolateName = event.isolate.name;
// If we get a line from a different isolate/stream, flush
// any pending output, even if it is not newline-terminated.
@@ -901,8 +975,15 @@
(_savedStream != null && streamName != _savedStream)) {
flush();
}
- String data = event.bytesAsString;
- bool hasNewline = data.endsWith('\n');
+ String data;
+ bool hasNewline;
+ if (event.kind == ServiceEvent.kLogging) {
+ data = event.logRecord["message"].valueAsString;
+ hasNewline = true;
+ } else {
+ data = event.bytesAsString;
+ hasNewline = data.endsWith('\n');
+ }
if (_savedLine != null) {
data = _savedLine + data;
_savedIsolate = null;
@@ -988,8 +1069,9 @@
new InfoCommand(this),
new IsolateCommand(this),
new RefreshCommand(this),
+ new LogCommand(this),
]);
- _stdioPrinter = new _VMStreamPrinter(this);
+ _consolePrinter = new _ConsoleStreamPrinter(this);
}
VM get vm => page.app.vm;
@@ -997,7 +1079,8 @@
void updateIsolate(Isolate iso) {
_isolate = iso;
if (_isolate != null) {
- if (exceptions != iso.exceptionsPauseInfo) {
+ if ((exceptions != iso.exceptionsPauseInfo) &&
+ (iso.exceptionsPauseInfo != null)) {
exceptions = iso.exceptionsPauseInfo;
console.print("Now pausing for $exceptions exceptions");
}
@@ -1133,7 +1216,7 @@
console.print('Paused at ${script.name}:${line}:${col}');
}
if (event.asyncContinuation != null) {
- console.print("Paused in async function: 'astep' available");
+ console.print("Paused in async function: 'anext' available");
}
});
}
@@ -1239,24 +1322,28 @@
case ServiceEvent.kInspect:
break;
+ case ServiceEvent.kLogging:
+ _consolePrinter.onEvent(event.logRecord['level'].name, event);
+ break;
+
default:
console.print('Unrecognized event: $event');
break;
}
}
- _VMStreamPrinter _stdioPrinter;
+ _ConsoleStreamPrinter _consolePrinter;
void flushStdio() {
- _stdioPrinter.flush();
+ _consolePrinter.flush();
}
void onStdout(ServiceEvent event) {
- _stdioPrinter.onEvent('stdout', event);
+ _consolePrinter.onEvent('stdout', event);
}
void onStderr(ServiceEvent event) {
- _stdioPrinter.onEvent('stderr', event);
+ _consolePrinter.onEvent('stderr', event);
}
static String _commonPrefix(String a, String b) {
@@ -1350,6 +1437,7 @@
Future<StreamSubscription> _debugSubscriptionFuture;
Future<StreamSubscription> _stdoutSubscriptionFuture;
Future<StreamSubscription> _stderrSubscriptionFuture;
+ Future<StreamSubscription> _logSubscriptionFuture;
@override
void attached() {
@@ -1387,7 +1475,8 @@
app.vm.listenEventStream(VM.kStdoutStream, debugger.onStdout);
_stderrSubscriptionFuture =
app.vm.listenEventStream(VM.kStderrStream, debugger.onStderr);
-
+ _logSubscriptionFuture =
+ app.vm.listenEventStream(Isolate.kLoggingStream, debugger.onEvent);
// Turn on the periodic poll timer for this page.
pollPeriod = const Duration(milliseconds:100);
@@ -1407,6 +1496,7 @@
@override
void detached() {
+ debugger.isolate = null;
cancelFutureSubscription(_isolateSubscriptionFuture);
_isolateSubscriptionFuture = null;
cancelFutureSubscription(_debugSubscriptionFuture);
@@ -1415,6 +1505,8 @@
_stdoutSubscriptionFuture = null;
cancelFutureSubscription(_stderrSubscriptionFuture);
_stderrSubscriptionFuture = null;
+ cancelFutureSubscription(_logSubscriptionFuture);
+ _logSubscriptionFuture = null;
super.detached();
}
}
@@ -1625,6 +1717,11 @@
DebuggerFrameElement.created() : super.created();
+
+ String makeExpandKey(String key) {
+ return '${frame.function.qualifiedName}/${key}';
+ }
+
bool matchFrame(Frame newFrame) {
return newFrame.function.id == frame.function.id;
}
@@ -1761,6 +1858,38 @@
DebuggerConsoleElement.created() : super.created();
+ /// Is [container] scrolled to the within [threshold] pixels of the bottom?
+ static bool _isScrolledToBottom(DivElement container, [int threshold = 2]) {
+ if (container == null) {
+ return false;
+ }
+ // scrollHeight -> complete height of element including scrollable area.
+ // clientHeight -> height of element on page.
+ // scrollTop -> how far is an element scrolled (from 0 to scrollHeight).
+ final distanceFromBottom =
+ container.scrollHeight - container.clientHeight - container.scrollTop;
+ const threshold = 2; // 2 pixel slop.
+ return distanceFromBottom <= threshold;
+ }
+
+ /// Scroll [container] so the bottom content is visible.
+ static _scrollToBottom(DivElement container) {
+ if (container == null) {
+ return;
+ }
+ // Adjust scroll so that the bottom of the content is visible.
+ container.scrollTop = container.scrollHeight - container.clientHeight;
+ }
+
+ void _append(HtmlElement span) {
+ var consoleTextElement = $['consoleText'];
+ bool autoScroll = _isScrolledToBottom(parent);
+ consoleTextElement.children.add(span);
+ if (autoScroll) {
+ _scrollToBottom(parent);
+ }
+ }
+
void print(String line, { bool newline:true }) {
var span = new SpanElement();
span.classes.add('normal');
@@ -1768,8 +1897,7 @@
if (newline) {
span.appendText('\n');
}
- $['consoleText'].children.add(span);
- span.scrollIntoView();
+ _append(span);
}
void printBold(String line, { bool newline:true }) {
@@ -1779,8 +1907,7 @@
if (newline) {
span.appendText('\n');
}
- $['consoleText'].children.add(span);
- span.scrollIntoView();
+ _append(span);
}
void printRed(String line, { bool newline:true }) {
@@ -1790,39 +1917,35 @@
if (newline) {
span.appendText('\n');
}
- $['consoleText'].children.add(span);
- span.scrollIntoView();
+ _append(span);
}
void printStdio(List<String> lines) {
- var lastSpan;
+ var consoleTextElement = $['consoleText'];
+ bool autoScroll = _isScrolledToBottom(parent);
for (var line in lines) {
var span = new SpanElement();
span.classes.add('green');
span.appendText(line);
span.appendText('\n');
- $['consoleText'].children.add(span);
- lastSpan = span;
+ consoleTextElement.children.add(span);
}
- if (lastSpan != null) {
- lastSpan.scrollIntoView();
+ if (autoScroll) {
+ _scrollToBottom(parent);
}
}
void printRef(Instance ref, { bool newline:true }) {
var refElement = new Element.tag('instance-ref');
refElement.ref = ref;
- $['consoleText'].children.add(refElement);
+ _append(refElement);
if (newline) {
this.newline();
}
- refElement.scrollIntoView();
}
void newline() {
- var br = new BRElement();
- $['consoleText'].children.add(br);
- br.scrollIntoView();
+ _append(new BRElement());
}
}
@@ -1890,4 +2013,3 @@
DebuggerInputElement.created() : super.created();
}
-
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index b2e6bfe..e0f5dce 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -270,7 +270,8 @@
<div class="memberItem">
<div class="memberName">{{ v['name']}}</div>
<div class="memberValue">
- <any-service-ref ref="{{ v['value'] }}">
+ <any-service-ref ref="{{ v['value'] }}"
+ expandKey="{{ makeExpandKey(v['name']) }}">
</any-service-ref>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/inbound_reference.html b/runtime/observatory/lib/src/elements/inbound_reference.html
index a820224..d7b9e5d 100644
--- a/runtime/observatory/lib/src/elements/inbound_reference.html
+++ b/runtime/observatory/lib/src/elements/inbound_reference.html
@@ -8,9 +8,10 @@
<template>
<link rel="stylesheet" href="css/shared.css">
<div>
- from <any-service-ref ref="{{ source }}"></any-service-ref>
- <template if="{{ slotIsArrayIndex }}">via [{{ slot }}]</template>
- <template if="{{ slotIsField }}">via <field-ref ref="{{ slot }}"></field-ref></template>
+ from
+ <template if="{{ slotIsArrayIndex }}">[{{ slot }}] of</template>
+ <template if="{{ slotIsField }}"><field-ref ref="{{ slot }}"></field-ref> of</template>
+ <any-service-ref ref="{{ source }}"></any-service-ref>
<curly-block callback="{{ expander() }}">
<div class="memberList">
diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart
index 19a87e1..86727ae 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref.dart
@@ -54,4 +54,8 @@
onDone();
}
}
+
+ String makeExpandKey(String key) {
+ return '${expandKey}/${key}';
+ }
}
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index d8a1def..4781972 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -38,17 +38,19 @@
<template if="{{ ref.isClosure }}">
<a on-click="{{ goto }}" _href="{{ url }}">
- {{ ref.function.qualifiedName }}
+ <em>Closure</em> ({{ ref.function.qualifiedName }})
</a>
</template>
<template if="{{ ref.isRegExp }}">
- <a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}({{ ref.pattern.valueAsString }})</em></a>
+ <a on-click="{{ goto }}" _href="{{ url }}">
+ <em>{{ ref.clazz.name }}</em> ({{ ref.pattern.valueAsString }})
+ </a>
</template>
<template if="{{ ref.isPlainInstance }}">
<a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}</em></a>
- <curly-block callback="{{ expander() }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="memberList">
<template repeat="{{ field in ref.fields }}">
<div class="memberItem">
@@ -56,7 +58,9 @@
{{ field['decl'].name }}
</div>
<div class="memberValue">
- <any-service-ref ref="{{ field['value'] }}"></any-service-ref>
+ <any-service-ref ref="{{ field['value'] }}"
+ expandKey="{{ makeExpandKey(field['decl'].name) }}">
+ </any-service-ref>
</div>
</div>
</template>
@@ -66,13 +70,14 @@
<template if="{{ ref.isList }}">
<a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}</em> ({{ ref.length }})</a>
- <curly-block callback="{{ expander() }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="memberList">
<template repeat="{{ index in ref.elements.asMap().keys }}">
<div class="memberItem">
<div class="memberName">[{{ index }}]</div>
<div class="memberValue">
- <any-service-ref ref="{{ ref.elements[index] }}">
+ <any-service-ref ref="{{ ref.elements[index] }}"
+ expandKey="{{ makeExpandKey(index.toString()) }}">
</any-service-ref>
</div>
</div>
@@ -83,15 +88,19 @@
<template if="{{ ref.isMap }}">
<a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}</em> ({{ ref.length }})</a>
- <curly-block callback="{{ expander() }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="memberList">
<template repeat="{{ association in ref.associations }}">
<div class="memberItem">
<div class="memberName">
- [<any-service-ref ref="{{ association['key'] }}"></any-service-ref>]
+ [<any-service-ref ref="{{ association['key'] }}"
+ expandKey="{{ makeExpandKey('key') }}">
+ </any-service-ref>]
</div>
<div class="memberValue">
- <any-service-ref ref="{{ association['value'] }}"></any-service-ref>
+ <any-service-ref ref="{{ association['value'] }}"
+ expandKey="{{ makeExpandKey('value') }}">
+ </any-service-ref>
</div>
</div>
</template>
@@ -101,7 +110,7 @@
<template if="{{ ref.isTypedData }}">
<a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}</em> ({{ ref.length }})</a>
- <curly-block callback="{{ expander() }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="memberList">
<template repeat="{{ index in ref.typedElements.asMap().keys }}">
<div class="memberItem">
@@ -115,12 +124,14 @@
<template if="{{ ref.isMirrorReference }}">
<a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}</em></a>
- <curly-block callback="{{ expander() }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="memberList">
<div class="memberItem">
<div class="memberName">referent</div>
<div class="memberValue">
- <any-service-ref ref="{{ ref.referent }}"></any-service-ref>
+ <any-service-ref ref="{{ ref.referent }}"
+ expandKey="{{ makeExpandKey('referent') }}">
+ </any-service-ref>
</div>
</div>
</div>
@@ -129,18 +140,22 @@
<template if="{{ ref.isWeakProperty }}">
<a on-click="{{ goto }}" _href="{{ url }}"><em>{{ ref.clazz.name }}</em></a>
- <curly-block callback="{{ expander() }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
<div class="memberList">
<div class="memberItem">
<div class="memberName">key</div>
<div class="memberValue">
- <any-service-ref ref="{{ ref.key }}"></any-service-ref>
+ <any-service-ref ref="{{ ref.key }}"
+ expandKey="{{ makeExpandKey('key') }}">
+ </any-service-ref>
</div>
</div>
<div class="memberItem">
<div class="memberName">value</div>
<div class="memberValue">
- <any-service-ref ref="{{ ref.value }}"></any-service-ref>
+ <any-service-ref ref="{{ ref.value }}"
+ expandKey="{{ makeExpandKey('value') }}">
+ </any-service-ref>
</div>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index 823b581..31dc45c 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -191,6 +191,11 @@
See <a on-click="{{ goto }}" _href="{{ gotoLink('/ports', isolate) }}">ports</a>
</div>
</div>
+ <div class="memberItem">
+ <div class="memberValue">
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/logging', isolate) }}">logging</a>
+ </div>
+ </div>
<!-- Temporarily disabled until UI for dart:io is acceptable.
<template if="{{ isolate.ioEnabled }}">
<div class="memberItem">
diff --git a/runtime/observatory/lib/src/elements/logging.dart b/runtime/observatory/lib/src/elements/logging.dart
new file mode 100644
index 0000000..8f26305
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/logging.dart
@@ -0,0 +1,201 @@
+// 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 logging_page;
+
+import 'dart:async';
+import 'dart:html';
+import 'observatory_element.dart';
+import 'package:logging/logging.dart';
+import 'package:observatory/service.dart';
+import 'package:observatory/app.dart';
+import 'package:observatory/elements.dart';
+import 'package:observatory/utils.dart';
+import 'package:polymer/polymer.dart';
+
+@CustomTag('logging-page')
+class LoggingPageElement extends ObservatoryElement {
+ static const _kPageSelector = '#page';
+ static const _kLogSelector = '#log';
+ static const _kSeverityLevelSelector = '#severityLevelSelector';
+
+ LoggingPageElement.created() : super.created();
+
+ domReady() {
+ super.domReady();
+ _insertLevels();
+ }
+
+ attached() {
+ super.attached();
+ _sub();
+ _resizeSubscription = window.onResize.listen((_) => _updatePageHeight());
+ _updatePageHeight();
+ // Turn on the periodic poll timer for this page.
+ pollPeriod = const Duration(milliseconds:100);
+ }
+
+ detached() {
+ super.detached();
+ if (_resizeSubscription != null) {
+ _resizeSubscription.cancel();
+ _resizeSubscription = null;
+ }
+ _unsub();
+ }
+
+ void onPoll() {
+ _flushPendingLogs();
+ }
+
+ _updatePageHeight() {
+ HtmlElement e = shadowRoot.querySelector(_kPageSelector);
+ final totalHeight = window.innerHeight;
+ final top = e.offset.top;
+ final bottomMargin = 32;
+ final mainHeight = totalHeight - top - bottomMargin;
+ e.style.setProperty('height', '${mainHeight}px');
+ }
+
+ _insertLevels() {
+ SelectElement severityLevelSelector =
+ shadowRoot.querySelector(_kSeverityLevelSelector);
+ severityLevelSelector.children.clear();
+ _maxLevelLabelLength = 0;
+ for (var level in Level.LEVELS) {
+ var option = new OptionElement();
+ option.value = level.value.toString();
+ option.label = level.name;
+ if (level.name.length > _maxLevelLabelLength) {
+ _maxLevelLabelLength = level.name.length;
+ }
+ severityLevelSelector.children.add(option);
+ }
+ severityLevelSelector.selectedIndex = 0;
+ severityLevel = Level.ALL.value.toString();
+ }
+
+ _reset() {
+ logRecords.clear();
+ _unsub();
+ _sub();
+ _renderFull();
+ }
+
+ _unsub() {
+ cancelFutureSubscription(_loggingSubscriptionFuture);
+ _loggingSubscriptionFuture = null;
+ }
+
+ _sub() {
+ if (_loggingSubscriptionFuture != null) {
+ // Already subscribed.
+ return;
+ }
+ _loggingSubscriptionFuture =
+ app.vm.listenEventStream(Isolate.kLoggingStream, _onEvent);
+ }
+
+ _append(Map logRecord) {
+ logRecords.add(logRecord);
+ if (_shouldDisplay(logRecord)) {
+ // Queue for display.
+ pendingLogRecords.add(logRecord);
+ }
+ }
+
+ Element _renderAppend(Map logRecord) {
+ DivElement logContainer = shadowRoot.querySelector(_kLogSelector);
+ var element = new DivElement();
+ element.classes.add('logItem');
+ element.classes.add(logRecord['level'].name);
+ element.appendText(
+ '${logRecord["level"].name.padLeft(_maxLevelLabelLength)} '
+ '${Utils.formatDateTime(logRecord["time"])} '
+ '${logRecord["message"].valueAsString}\n');
+ logContainer.children.add(element);
+ return element;
+ }
+
+ _renderFull() {
+ DivElement logContainer = shadowRoot.querySelector(_kLogSelector);
+ logContainer.children.clear();
+ pendingLogRecords.clear();
+ for (var logRecord in logRecords) {
+ if (_shouldDisplay(logRecord)) {
+ _renderAppend(logRecord);
+ }
+ }
+ _scrollToBottom(logContainer);
+ }
+
+ /// Is [container] scrolled to the within [threshold] pixels of the bottom?
+ static bool _isScrolledToBottom(DivElement container, [int threshold = 2]) {
+ if (container == null) {
+ return false;
+ }
+ // scrollHeight -> complete height of element including scrollable area.
+ // clientHeight -> height of element on page.
+ // scrollTop -> how far is an element scrolled (from 0 to scrollHeight).
+ final distanceFromBottom =
+ container.scrollHeight - container.clientHeight - container.scrollTop;
+ const threshold = 2; // 2 pixel slop.
+ return distanceFromBottom <= threshold;
+ }
+
+ /// Scroll [container] so the bottom content is visible.
+ static _scrollToBottom(DivElement container) {
+ if (container == null) {
+ return;
+ }
+ // Adjust scroll so that the bottom of the content is visible.
+ container.scrollTop = container.scrollHeight - container.clientHeight;
+ }
+
+ _flushPendingLogs() {
+ DivElement logContainer = shadowRoot.querySelector(_kLogSelector);
+ bool autoScroll = _isScrolledToBottom(logContainer);
+ for (var logRecord in pendingLogRecords) {
+ _renderAppend(logRecord);
+ }
+ if (autoScroll) {
+ _scrollToBottom(logContainer);
+ }
+ pendingLogRecords.clear();
+ }
+
+ _onEvent(ServiceEvent event) {
+ assert(event.kind == Isolate.kLoggingStream);
+ _append(event.logRecord);
+ }
+
+ void isolateChanged(oldValue) {
+ _reset();
+ }
+
+ void severityLevelChanged(oldValue) {
+ _severityLevelValue = int.parse(severityLevel);
+ _renderFull();
+ }
+
+ Future clear() {
+ logRecords.clear();
+ pendingLogRecords.clear();
+ _renderFull();
+ return new Future.value(null);
+ }
+
+ bool _shouldDisplay(Map logRecord) {
+ return logRecord['level'].value >= _severityLevelValue;
+ }
+
+ @observable Isolate isolate;
+ @observable String severityLevel;
+ int _severityLevelValue = 0;
+ int _maxLevelLabelLength = 0;
+ Future<StreamSubscription> _loggingSubscriptionFuture;
+ StreamSubscription _resizeSubscription;
+ final List<Map> logRecords = new List<Map>();
+ final List<Map> pendingLogRecords = new List<Map>();
+}
diff --git a/runtime/observatory/lib/src/elements/logging.html b/runtime/observatory/lib/src/elements/logging.html
new file mode 100644
index 0000000..a3a36a1
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/logging.html
@@ -0,0 +1,77 @@
+<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="code_ref.html">
+<link rel="import" href="function_ref.html">
+<link rel="import" href="nav_bar.html">
+<link rel="import" href="observatory_element.html">
+<link rel="import" href="sliding_checkbox.html">
+<link rel="import" href="view_footer.html">
+
+<polymer-element name="logging-page" extends="observatory-element">
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .outlined {
+ -webkit-box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
+ -moz-box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
+ box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
+ margin: 4px;
+ }
+ .logItem {
+ font: normal 14px consolas, courier, monospace;
+ white-space: pre;
+ line-height: 125%;
+ width: 100%;
+ }
+ .FINEST {
+ background-color: #FAFAFA;
+ }
+ .FINER {
+ background-color: #ECEFF1;
+ }
+ .FINE {
+ background-color: #EFEBE9;
+ }
+ .CONFIG {
+ background-color: #FFF3E0;
+ }
+ .INFO {
+ background-color: #F1F8E9;
+ }
+ .WARNING {
+ background-color: #FFE0B2;
+ }
+ .SEVERE {
+ background-color: #FFCCBC;
+ }
+ .SHOUT {
+ background-color: #FFCDD2;
+ }
+ #log {
+ height: 100%;
+ width: 100%;
+ overflow-y: auto;
+ padding: 8px;
+ }
+ .fill {
+ height: 80%;
+ width: 100%;
+ }
+ </style>
+ <nav-bar>
+ <top-nav-menu></top-nav-menu>
+ <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
+ <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
+ <nav-menu link="{{ makeLink('/logging', isolate) }}" anchor="logging" last="{{ true }}"></nav-menu>
+ <nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
+ </nav-bar>
+ <div id="page" class="content-centered-big">
+ <span>Show messages with severity <select id="severityLevelSelector" value="{{ severityLevel }}"></select> and higher</span>
+ <hr>
+ <div class="flex-row fill">
+ <div id="log" class="outlined"></div>
+ </div>
+ </div>
+ </template>
+</polymer-element>
+
+<script type="application/dart" src="logging.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/metrics.dart b/runtime/observatory/lib/src/elements/metrics.dart
index b7e4e79..73343c5 100644
--- a/runtime/observatory/lib/src/elements/metrics.dart
+++ b/runtime/observatory/lib/src/elements/metrics.dart
@@ -27,13 +27,22 @@
if ((isolate != null) && (page != null) &&
(page.selectedMetricId != null)) {
selectedMetric = isolate.dartMetrics[page.selectedMetricId];
- if (selectedMetric == null) {
- selectedMetric = isolate.nativeMetrics[page.selectedMetricId];
+ if (selectedMetric != null) {
+ return;
}
+ selectedMetric = isolate.nativeMetrics[page.selectedMetricId];
}
if ((selectedMetric == null) && (isolate != null)) {
- var values = isolate.dartMetrics.values;
- if (values != null) {
+ var values = isolate.dartMetrics.values.toList();
+ if ((values != null) && (values.length > 0)) {
+ // Fall back and pick the first isolate metric.
+ selectedMetric = values.first;
+ }
+ if (selectedMetric != null) {
+ return;
+ }
+ values = isolate.nativeMetrics.values.toList();
+ if ((values != null) && (values.length > 0)) {
// Fall back and pick the first isolate metric.
selectedMetric = values.first;
}
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
index 63c78a1..c4ce618 100644
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ b/runtime/observatory/lib/src/elements/object_common.html
@@ -46,7 +46,7 @@
<template if="{{ path == null }}">
<eval-link callback="{{ retainingPath }}"
label="[find]"
- expr="10">
+ expr="20">
</eval-link>
</template>
<template if="{{ path != null }}">
@@ -54,13 +54,16 @@
<div class="memberItem">
<div class="memberName">[{{ element['index']}}]</div>
<div class="memberValue">
- <any-service-ref ref="{{ element['value'] }}"></any-service-ref>
<template if="{{ element['parentField'] != null }}">
- in <field-ref ref="{{ element['parentField'] }}"></field-ref> of
+ from <field-ref ref="{{ element['parentField'] }}"></field-ref> of
</template>
<template if="{{ element['parentListIndex'] != null }}">
- in [{{ element['parentListIndex'] }}] of
+ from [{{ element['parentListIndex'] }}] of
</template>
+ <template if="{{ element['_parentWordOffset'] != null }}">
+ from word[{{ element['_parentWordOffset'] }}] of
+ </template>
+ <any-service-ref ref="{{ element['value'] }}"></any-service-ref>
</div>
</div>
</template>
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index 7c5ff02..d823b86 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -14,6 +14,7 @@
class ServiceRefElement extends ObservatoryElement {
@published ServiceObject ref;
@published bool internal = false;
+ @published String expandKey;
ServiceRefElement.created() : super.created();
void refChanged(oldValue) {
@@ -61,6 +62,7 @@
@CustomTag('any-service-ref')
class AnyServiceRefElement extends ObservatoryElement {
@published ServiceObject ref;
+ @published String expandKey;
AnyServiceRefElement.created() : super.created();
Element _constructElementForRef() {
@@ -106,6 +108,9 @@
case 'Sentinel':
ServiceRefElement element = new Element.tag('instance-ref');
element.ref = ref;
+ if (expandKey != null) {
+ element.expandKey = expandKey;
+ }
return element;
default:
SpanElement element = new Element.tag('span');
diff --git a/runtime/observatory/lib/src/elements/view_footer.html b/runtime/observatory/lib/src/elements/view_footer.html
index aa82cca..59862b5 100644
--- a/runtime/observatory/lib/src/elements/view_footer.html
+++ b/runtime/observatory/lib/src/elements/view_footer.html
@@ -12,7 +12,7 @@
</a>
</p>
<p>
- <a href="https://code.google.com/p/dart/issues/entry?template=Observatory" style="font-size:90%">
+ <a href="https://github.com/dart-lang/sdk/issues/new?title=Observatory:&body=Observatory%20Feedback" style="font-size:90%">
File a bug report
</a>
</p>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index fa73cf6..9124595 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -954,6 +954,7 @@
/// State for a running isolate.
class Isolate extends ServiceObjectOwner with Coverage {
+ static const kLoggingStream = '_Logging';
@reflectable VM get vm => owner;
@reflectable Isolate get isolate => this;
@observable int number;
@@ -1396,6 +1397,67 @@
return invokeRpc('resume', {'step': 'Out'});
}
+
+ static const int kFirstResume = 0;
+ static const int kSecondResume = 1;
+ /// result[kFirstResume] completes after the inital resume. The UI should
+ /// wait on this future because some other breakpoint may be hit before the
+ /// async continuation.
+ /// result[kSecondResume] completes after the second resume. Tests should
+ /// wait on this future to avoid confusing the pause event at the
+ /// state-machine switch with the pause event after the state-machine switch.
+ List<Future> asyncStepOver() {
+ Completer firstResume = new Completer();
+ Completer secondResume = new Completer();
+ var subscription;
+
+ handleError(error) {
+ if (subscription != null) {
+ subscription.cancel();
+ subscription = null;
+ }
+ firstResume.completeError(error);
+ secondResume.completeError(error);
+ }
+
+ if ((pauseEvent == null) ||
+ (pauseEvent.kind != ServiceEvent.kPauseBreakpoint) ||
+ (pauseEvent.asyncContinuation == null)) {
+ handleError(new Exception("No async continuation available"));
+ } else {
+ Instance continuation = pauseEvent.asyncContinuation;
+ assert(continuation.isClosure);
+ addBreakOnActivation(continuation).then((Breakpoint continuationBpt) {
+ vm.getEventStream(VM.kDebugStream).then((stream) {
+ var onResume = firstResume;
+ subscription = stream.listen((ServiceEvent event) {
+ if ((event.kind == ServiceEvent.kPauseBreakpoint) &&
+ (event.breakpoint == continuationBpt)) {
+ // We are stopped before state-machine dispatch; step-over to
+ // reach user code.
+ removeBreakpoint(continuationBpt).then((_) {
+ onResume = secondResume;
+ stepOver().catchError(handleError);
+ });
+ } else if (event.kind == ServiceEvent.kResume) {
+ if (onResume == secondResume) {
+ subscription.cancel();
+ subscription = null;
+ }
+ if (onResume != null) {
+ onResume.complete(this);
+ onResume = null;
+ }
+ }
+ });
+ resume().catchError(handleError);
+ }).catchError(handleError);
+ }).catchError(handleError);
+ }
+
+ return [firstResume.future, secondResume.future];
+ }
+
Future setName(String newName) {
return invokeRpc('setName', {'name': newName});
}
@@ -1591,6 +1653,15 @@
String toString() => 'DartError($message)';
}
+Level _findLogLevel(int value) {
+ for (var level in Level.LEVELS) {
+ if (level.value == value) {
+ return level;
+ }
+ }
+ return new Level('$value', value);
+}
+
/// A [ServiceEvent] is an asynchronous event notification from the vm.
class ServiceEvent extends ServiceObject {
/// The possible 'kind' values.
@@ -1611,6 +1682,7 @@
static const kInspect = 'Inspect';
static const kDebuggerSettingsUpdate = '_DebuggerSettingsUpdate';
static const kConnectionClosed = 'ConnectionClosed';
+ static const kLogging = '_Logging';
ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -1629,6 +1701,7 @@
@observable String reason;
@observable String exceptions;
@observable String bytesAsString;
+ @observable Map logRecord;
int chunkIndex, chunkCount, nodeCount;
@observable bool get isPauseEvent {
@@ -1691,6 +1764,12 @@
var bytes = decodeBase64(map['bytes']);
bytesAsString = UTF8.decode(bytes);
}
+ if (map['logRecord'] != null) {
+ logRecord = map['logRecord'];
+ logRecord['time'] =
+ new DateTime.fromMillisecondsSinceEpoch(logRecord['time'].toInt());
+ logRecord['level'] = _findLogLevel(logRecord['level']);
+ }
}
String toString() {
diff --git a/runtime/observatory/lib/tracer.dart b/runtime/observatory/lib/tracer.dart
index 1453c3c..ffe0892 100644
--- a/runtime/observatory/lib/tracer.dart
+++ b/runtime/observatory/lib/tracer.dart
@@ -60,7 +60,7 @@
_current = null;
}
}
-
+
// The tracer subscribes to all logging events.
StreamSubscription loggerSub = null;
@@ -93,5 +93,5 @@
var event = new TraceEvent.msg(_time.elapsedMicroseconds, message, map);
events.add(event);
return event;
- }
+ }
}
diff --git a/runtime/observatory/lib/utils.dart b/runtime/observatory/lib/utils.dart
index c696529..cfc447c 100644
--- a/runtime/observatory/lib/utils.dart
+++ b/runtime/observatory/lib/utils.dart
@@ -135,6 +135,13 @@
return '${seconds}s';
}
+ static String formatDateTime(DateTime now) {
+ return '${now.year}-${now.month}-${now.day} '
+ '${now.hour.toString().padLeft(2)}:'
+ '${now.minute.toString().padLeft(2)}:'
+ '${now.second.toString().padLeft(2)}';
+ }
+
static String formatSeconds(double x) {
return x.toStringAsFixed(2);
}
diff --git a/runtime/observatory/observatory.gypi b/runtime/observatory/observatory.gypi
index 156caad..50cd334 100644
--- a/runtime/observatory/observatory.gypi
+++ b/runtime/observatory/observatory.gypi
@@ -43,10 +43,7 @@
'target_name': 'build_observatory',
'type': 'none',
'dependencies': [
- 'dart_bootstrap#host',
'fetch_observatory_deps#host',
- # We use packages for building
- '../pkg/pkg.gyp:pkg_packages#target',
],
'toolsets': ['host'],
'includes': [
@@ -57,13 +54,11 @@
'action_name': 'pub_build_observatory',
'inputs': [
'../../tools/observatory_tool.py',
- '<(SHARED_INTERMEDIATE_DIR)/packages.stamp',
'pubspec.lock',
'<@(_sources)',
],
'outputs': [
'<(PRODUCT_DIR)/observatory/build/web/index.html',
- '<(PRODUCT_DIR)/observatory/build/web/index.html.polymer.bootstrap.dart.js',
],
'action': [
'python',
@@ -81,11 +76,9 @@
'inputs': [
'../../tools/observatory_tool.py',
'<(PRODUCT_DIR)/observatory/build/web/index.html',
- '<(PRODUCT_DIR)/observatory/build/web/index.html.polymer.bootstrap.dart.js',
],
'outputs': [
'<(PRODUCT_DIR)/observatory/deployed/web/index.html',
- '<(PRODUCT_DIR)/observatory/deployed/web/index.html.polymer.bootstrap.dart.js',
],
'action': [
'python',
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index 9445912..e02a5e7 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -103,6 +103,8 @@
'lib/src/elements/library_ref.html',
'lib/src/elements/library_view.dart',
'lib/src/elements/library_view.html',
+ 'lib/src/elements/logging.dart',
+ 'lib/src/elements/logging.html',
'lib/src/elements/metrics.dart',
'lib/src/elements/metrics.html',
'lib/src/elements/nav_bar.dart',
diff --git a/runtime/observatory/tests/service/allocations_test.dart b/runtime/observatory/tests/service/allocations_test.dart
index 4708811..6cd953f 100644
--- a/runtime/observatory/tests/service/allocations_test.dart
+++ b/runtime/observatory/tests/service/allocations_test.dart
@@ -25,8 +25,8 @@
expect(lib.classes.length, equals(1));
return lib.classes.first.load().then((Class fooClass) {
expect(fooClass.name, equals('Foo'));
- expect(fooClass.newSpace.accumulated.instances +
- fooClass.oldSpace.accumulated.instances, equals(3));
+ expect(fooClass.newSpace.current.instances +
+ fooClass.oldSpace.current.instances, equals(3));
});
}),
diff --git a/runtime/observatory/tests/service/async_continuation_test.dart b/runtime/observatory/tests/service/async_continuation_test.dart
index 5b65bf8..781f7ca 100644
--- a/runtime/observatory/tests/service/async_continuation_test.dart
+++ b/runtime/observatory/tests/service/async_continuation_test.dart
@@ -66,7 +66,7 @@
if (bp == bp1) {
await stoppedAtLine(15)(isolate);
print(event.asyncContinuation);
- expect(event.asyncContinuation.isNull, isTrue);
+ expect(event.asyncContinuation, equals(null));
isolate.resume();
bp1_hit.complete(null);
}
diff --git a/runtime/observatory/tests/service/async_next_test.dart b/runtime/observatory/tests/service/async_next_test.dart
new file mode 100644
index 0000000..2e9a0f2
--- /dev/null
+++ b/runtime/observatory/tests/service/async_next_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override --verbose_debug
+
+import 'package:observatory/service_io.dart';
+import 'test_helper.dart';
+import 'dart:developer';
+
+foo() async { }
+
+doAsync(stop) async {
+ if (stop) debugger();
+ await foo(); // Line 14.
+ await foo(); // Line 15.
+ await foo(); // Line 16.
+ return null;
+}
+
+testMain() {
+ // With two runs of doAsync floating around, async step should only cause
+ // us to stop in the run we started in.
+ doAsync(false);
+ doAsync(true);
+}
+
+asyncNext(Isolate isolate) async {
+ return isolate.asyncStepOver()[Isolate.kSecondResume];
+}
+
+var tests = [
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(14),
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(15),
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(16),
+ resumeIsolate,
+];
+
+main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/async_scope_test.dart b/runtime/observatory/tests/service/async_scope_test.dart
index 3150b50..981ea26 100644
--- a/runtime/observatory/tests/service/async_scope_test.dart
+++ b/runtime/observatory/tests/service/async_scope_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
-import 'dart:async';
import 'dart:developer';
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -13,14 +12,14 @@
doAsync(param1) async {
var local1 = param1 + 1;
- foo(); // Line 16
- await null;
+ foo(); // Line 15
+ await local1;
}
doAsyncStar(param2) async* {
var local2 = param2 + 1;
- foo(); // Line 22
- yield null;
+ foo(); // Line 21
+ yield local2;
}
testeeDo() {
@@ -54,17 +53,17 @@
var tests = [
hasStoppedAtBreakpoint, // debugger()
- setBreakpointAtLine(16),
- setBreakpointAtLine(22),
+ setBreakpointAtLine(15),
+ setBreakpointAtLine(21),
resumeIsolate,
hasStoppedAtBreakpoint,
- stoppedAtLine(16),
+ stoppedAtLine(15),
checkAsyncVarDescriptors,
resumeIsolate,
hasStoppedAtBreakpoint,
- stoppedAtLine(22),
+ stoppedAtLine(21),
checkAsyncStarVarDescriptors,
resumeIsolate,
];
diff --git a/runtime/observatory/tests/service/async_step_test.dart b/runtime/observatory/tests/service/async_step_test.dart
deleted file mode 100644
index fb0fafd..0000000
--- a/runtime/observatory/tests/service/async_step_test.dart
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override --verbose_debug
-
-import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-import 'test_helper.dart';
-import 'dart:developer';
-
-foo() async { }
-
-doAsync(stop) async {
- if (stop) debugger();
- await foo(); // Line 15.
- await foo(); // Line 16.
- await foo(); // Line 17.
- return null;
-}
-
-testMain() {
- // With two runs of doAsync floating around, async step should only cause
- // us to stop in the run we started in.
- doAsync(false);
- doAsync(true);
-}
-
-asyncStep(Isolate isolate) async {
- await isolate.reload(); // isolate.pauseEvent may be stale
- ServiceEvent event = isolate.pauseEvent;
- print("Pause event is $event");
- expect(event, isNotNull);
- expect(event.kind, equals(ServiceEvent.kPauseBreakpoint));
-
- // 1. Set breakpoint for the continuation and resume the isolate.
- Instance continuation = event.asyncContinuation;
- print("Async continuation is $continuation");
- if (continuation == null) {
- print(await isolate.getStack());
- }
- expect(continuation.isClosure, isTrue);
-
- var bpt = await isolate.addBreakOnActivation(continuation);
- print("Async step to $bpt");
- expect(bpt is Breakpoint, isTrue);
-
- await isolate.resume();
- await hasStoppedAtBreakpoint(isolate);
- print("Big step to: ${isolate.pauseEvent}");
-
- // 2. Step past the state-machine dispatch.
- await isolate.stepOver();
- await hasStoppedAtBreakpoint(isolate);
- print("Small step to: ${isolate.pauseEvent}");
-}
-
-var tests = [
- hasStoppedAtBreakpoint,
- stoppedAtLine(15),
- asyncStep,
- stoppedAtLine(16),
- asyncStep,
- stoppedAtLine(17),
- resumeIsolate,
-];
-
-main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/capture_stdio_test.dart b/runtime/observatory/tests/service/capture_stdio_test.dart
index b9673cf..56a1451 100644
--- a/runtime/observatory/tests/service/capture_stdio_test.dart
+++ b/runtime/observatory/tests/service/capture_stdio_test.dart
@@ -85,5 +85,5 @@
},
];
-
+
main(args) => runIsolateTests(args, tests, testeeConcurrent: test);
diff --git a/runtime/observatory/tests/service/crash_dump_test.dart b/runtime/observatory/tests/service/crash_dump_test.dart
new file mode 100644
index 0000000..8b60567
--- /dev/null
+++ b/runtime/observatory/tests/service/crash_dump_test.dart
@@ -0,0 +1,34 @@
+// 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 crash_dump_test;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'package:observatory/service_io.dart';
+
+import 'test_helper.dart';
+
+Future warmup() async {
+ print('hi');
+}
+
+var tests = [
+ (VM vm) async {
+ HttpClient client = new HttpClient();
+ var request =
+ await client.getUrl(Uri.parse('$serviceHttpAddress/_getCrashDump'));
+ var response = await request.close();
+ Completer completer = new Completer();
+ StringBuffer sb = new StringBuffer();
+ response.transform(UTF8.decoder).listen((chunk) {
+ sb.write(chunk);
+ }, onDone: () => completer.complete(sb.toString()));
+ var responseString = await completer.future;
+ JSON.decode(responseString);
+ }
+];
+
+main(args) async => runVMTests(args, tests, testeeBefore:warmup);
diff --git a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
index dbb43c7..f773dae 100644
--- a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
@@ -78,7 +78,7 @@
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['elements'][0]['parentField']['name'], equals('x'));
+ expect(result['elements'][1]['parentField']['name'], equals('x'));
expect(result['elements'][2]['value']['name'], equals('globalObject'));
},
@@ -91,7 +91,7 @@
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['elements'][0]['parentField']['name'], equals('y'));
+ expect(result['elements'][1]['parentField']['name'], equals('y'));
expect(result['elements'][2]['value']['name'], equals('globalObject'));
},
@@ -104,7 +104,7 @@
};
var result = await isolate.invokeRpcNoUpgrade('_getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['elements'][0]['parentListIndex'], equals(12));
+ expect(result['elements'][1]['parentListIndex'], equals(12));
expect(result['elements'][2]['value']['name'], equals('globalList'));
},
];
diff --git a/runtime/observatory/tests/service/get_stack_rpc_test.dart b/runtime/observatory/tests/service/get_stack_rpc_test.dart
index f3736e6..7210794 100644
--- a/runtime/observatory/tests/service/get_stack_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_stack_rpc_test.dart
@@ -19,7 +19,7 @@
void periodicTask(_) {
port.sendPort.send(34);
- developer.debugger(msg: "foo", when: true); // We will be at the next line.
+ developer.debugger(message: "fo", when: true); // We will be at the next line.
counter++;
if (counter % 300 == 0) {
print('counter = $counter');
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index cb03444..636eb71 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
(VM vm) async {
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
- expect(result['major'], equals(1));
+ expect(result['major'], equals(2));
expect(result['minor'], equals(0));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
diff --git a/runtime/observatory/tests/service/logging_test.dart b/runtime/observatory/tests/service/logging_test.dart
new file mode 100644
index 0000000..cefa67b
--- /dev/null
+++ b/runtime/observatory/tests/service/logging_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer' as developer;
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'package:logging/logging.dart';
+
+import 'test_helper.dart';
+
+void init() {
+ Logger.root.level = Level.ALL;
+ Logger.root.onRecord.listen((logRecord) {
+ developer.log(
+ logRecord.message,
+ time: logRecord.time,
+ sequenceNumber: logRecord.sequenceNumber,
+ level: logRecord.level.value,
+ name: logRecord.loggerName,
+ zone: null,
+ error: logRecord.error,
+ stackTrace: logRecord.stackTrace);
+ });
+}
+
+void run() {
+ developer.debugger();
+ Logger.root.fine('Hey Buddy!');
+ developer.debugger();
+ Logger.root.info('YES');
+}
+
+var tests = [
+ hasStoppedAtBreakpoint,
+ resumeIsolateAndAwaitEvent(Isolate.kLoggingStream, (ServiceEvent event) {
+ expect(event.kind, equals(ServiceEvent.kLogging));
+ expect(event.logRecord['sequenceNumber'], equals(0));
+ expect(event.logRecord['message'].valueAsString, equals('Hey Buddy!'));
+ expect(event.logRecord['level'], equals(Level.FINE));
+ expect(event.logRecord['time'], new isInstanceOf<DateTime>());
+ }),
+ resumeIsolateAndAwaitEvent(Isolate.kLoggingStream, (ServiceEvent event) {
+ expect(event.kind, equals(ServiceEvent.kLogging));
+ expect(event.logRecord['sequenceNumber'], equals(1));
+ expect(event.logRecord['level'], equals(Level.INFO));
+ expect(event.logRecord['message'].valueAsString, equals('YES'));
+ expect(event.logRecord['time'], new isInstanceOf<DateTime>());
+ }),
+];
+
+main(args) => runIsolateTests(args,
+ tests,
+ testeeBefore: init,
+ testeeConcurrent: run);
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 53520c4..4c492ed 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -1,7 +1,6 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override --checked
library test_helper;
@@ -87,6 +86,10 @@
typedef Future IsolateTest(Isolate isolate);
typedef Future VMTest(VM vm);
+/// Will be set to the http address of the VM's service protocol before
+/// any tests are invoked.
+String serviceHttpAddress;
+
/// Runs [tests] in sequence, each of which should take an [Isolate] and
/// return a [Future]. Code for setting up state can run before and/or
/// concurrently with the tests. Uses [mainArgs] to determine whether
@@ -113,6 +116,7 @@
port = 8181;
}
String addr = 'ws://localhost:$port/ws';
+ serviceHttpAddress = 'http://localhost:$port';
var testIndex = 1;
var totalTests = tests.length;
var name = Platform.script.pathSegments.last;
@@ -167,7 +171,8 @@
print('Breakpoint reached');
subscription.cancel();
if (completer != null) {
- completer.complete(isolate);
+ // Reload to update isolate.pauseEvent.
+ completer.complete(isolate.reload());
completer = null;
}
}
@@ -237,6 +242,30 @@
}
+Future resumeAndAwaitEvent(Isolate isolate, stream, onEvent) async {
+ Completer completer = new Completer();
+ var sub;
+ sub = await isolate.vm.listenEventStream(
+ stream,
+ (ServiceEvent event) {
+ var r = onEvent(event);
+ if (r is! Future) {
+ r = new Future.value(r);
+ }
+ r.then((x) => sub.cancel().then((_) {
+ completer.complete();
+ }));
+ });
+ await isolate.resume();
+ return completer.future;
+}
+
+IsolateTest resumeIsolateAndAwaitEvent(stream, onEvent) {
+ return (Isolate isolate) async =>
+ resumeAndAwaitEvent(isolate, stream, onEvent);
+}
+
+
Future<Class> getClassFromRootLib(Isolate isolate, String className) async {
Library rootLib = await isolate.rootLibrary.load();
for (var i = 0; i < rootLib.classes.length; i++) {
@@ -275,6 +304,7 @@
port = 8181;
}
String addr = 'ws://localhost:$port/ws';
+ serviceHttpAddress = 'http://localhost:$port';
var testIndex = 1;
var totalTests = tests.length;
var name = Platform.script.pathSegments.last;
diff --git a/runtime/observatory/tests/ui/log.dart b/runtime/observatory/tests/ui/log.dart
new file mode 100644
index 0000000..8bd1940
--- /dev/null
+++ b/runtime/observatory/tests/ui/log.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:developer' as developer;
+import 'package:logging/logging.dart';
+
+main() {
+ Logger.root.level = Level.ALL;
+ Logger.root.onRecord.listen((logRecord) {
+ developer.log(
+ logRecord.message,
+ time: logRecord.time,
+ sequenceNumber: logRecord.sequenceNumber,
+ level: logRecord.level.value,
+ name: logRecord.loggerName,
+ zone: null,
+ error: logRecord.error,
+ stackTrace: logRecord.stackTrace);
+ });
+ new Timer.periodic(new Duration(seconds: 1), (t) {
+ Logger.root.info('INFO MESSAGE');
+ });
+ new Timer.periodic(new Duration(seconds: 1), (t) {
+ Logger.root.fine('FINE MESSAGE');
+ });
+}
diff --git a/runtime/observatory/tests/ui/log.txt b/runtime/observatory/tests/ui/log.txt
new file mode 100644
index 0000000..0f64917
--- /dev/null
+++ b/runtime/observatory/tests/ui/log.txt
@@ -0,0 +1,6 @@
+0. Run dart --observe log.dart
+1. Visit main isolate's logging page.
+2. You should see 'INFO MESSAGE' and 'FINE MESSAGE'.
+3. Adjust the level to be 'INFO' and see that 'FINE' messages are hidden.
+4. Adjust the level to be 'FINE' and see that all messages are displayed.
+5. Adjust the level to be 'SHOUT' and see that no messages are displayed.
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 8bf2fb4..d0ffb46 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -4,7 +4,7 @@
# These tests are expected to crash on all platforms.
cc/ArrayNew_Overflow_Crash: Crash
-cc/AllocGeneric_Overflow: Crash
+cc/AllocGeneric_Overflow: Crash, Timeout
cc/CodeImmutability: Crash
cc/SNPrint_BadArgs: Skip
diff --git a/runtime/vm/allocation.cc b/runtime/vm/allocation.cc
index b6ca73e..92e2885 100644
--- a/runtime/vm/allocation.cc
+++ b/runtime/vm/allocation.cc
@@ -30,11 +30,11 @@
}
-void StackResource::UnwindAbove(Isolate* isolate, StackResource* new_top) {
- StackResource* current_resource = isolate->top_resource();
+void StackResource::UnwindAbove(Thread* thread, StackResource* new_top) {
+ StackResource* current_resource = thread->top_resource();
while (current_resource != new_top) {
current_resource->~StackResource();
- current_resource = isolate->top_resource();
+ current_resource = thread->top_resource();
}
}
diff --git a/runtime/vm/allocation.h b/runtime/vm/allocation.h
index f6b74b8..3947f0e 100644
--- a/runtime/vm/allocation.h
+++ b/runtime/vm/allocation.h
@@ -70,12 +70,10 @@
// The thread that owns this resource.
Thread* thread() const { return thread_; }
- // Destroy stack resources of isolate until top exit frame.
- // TODO(koda): Migrate to Thread.
- static void Unwind(Isolate* isolate) { UnwindAbove(isolate, NULL); }
- // TODO(koda): Migrate to Thread.
- // Destroy stack resources of isolate above new_top, exclusive.
- static void UnwindAbove(Isolate* isolate, StackResource* new_top);
+ // Destroy stack resources of thread until top exit frame.
+ static void Unwind(Thread* thread) { UnwindAbove(thread, NULL); }
+ // Destroy stack resources of thread above new_top, exclusive.
+ static void UnwindAbove(Thread* thread, StackResource* new_top);
private:
void Init(Thread* thread) {
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index 3f3e61a..9d17b1b 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -312,9 +312,10 @@
return Object::empty_object_pool().raw();
}
const ObjectPool& result = ObjectPool::Handle(ObjectPool::New(len));
+ const TypedData& info_array = TypedData::Handle(result.info_array());
for (intptr_t i = 0; i < len; ++i) {
ObjectPool::EntryType info = object_pool_[i].type_;
- result.SetInfoAt(i, info);
+ info_array.SetInt8(i, static_cast<int8_t>(info));
if (info == ObjectPool::kTaggedObject) {
result.SetObjectAt(i, *object_pool_[i].obj_);
} else {
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 0e3fb7e..bd2a6e7 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1525,11 +1525,16 @@
}
+intptr_t Assembler::FindImmediate(int32_t imm) {
+ return object_pool_wrapper_.FindImmediate(imm);
+}
+
+
// Uses a code sequence that can easily be decoded.
void Assembler::LoadWordFromPoolOffset(Register rd,
int32_t offset,
Condition cond) {
- ASSERT(allow_constant_pool());
+ ASSERT(constant_pool_allowed());
ASSERT(rd != PP);
int32_t offset_mask = 0;
if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) {
@@ -1555,6 +1560,7 @@
Instructions::HeaderSize() - Instructions::object_pool_offset() +
CodeSize() + Instr::kPCReadOffset;
LoadFromOffset(kWord, PP, PC, -object_pool_pc_dist);
+ set_constant_pool_allowed(true);
}
@@ -1576,7 +1582,7 @@
// Smis and VM heap objects are never relocated; do not use object pool.
if (object.IsSmi()) {
LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
- } else if (object.InVMHeap() || !allow_constant_pool()) {
+ } else if (object.InVMHeap() || !constant_pool_allowed()) {
// 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);
@@ -2678,6 +2684,12 @@
}
+void Assembler::Branch(const StubEntry& stub_entry, Condition cond) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ Branch(&label, cond);
+}
+
+
void Assembler::BranchPatchable(const ExternalLabel* label) {
// Use a fixed size code sequence, since a function prologue may be patched
// with this branch sequence.
@@ -2688,12 +2700,24 @@
}
+void Assembler::BranchPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchPatchable(&label);
+}
+
+
void Assembler::BranchLink(const ExternalLabel* label) {
LoadImmediate(LR, label->address()); // Target address is never patched.
blx(LR); // Use blx instruction so that the return branch prediction works.
}
+void Assembler::BranchLink(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLink(&label);
+}
+
+
void Assembler::BranchLink(const ExternalLabel* label, Patchability patchable) {
// Make sure that class CallPattern is able to patch the label referred
// to by this code sequence.
@@ -2706,11 +2730,24 @@
}
+void Assembler::BranchLink(const StubEntry& stub_entry,
+ Patchability patchable) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLink(&label, patchable);
+}
+
+
void Assembler::BranchLinkPatchable(const ExternalLabel* label) {
BranchLink(label, kPatchable);
}
+void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLinkPatchable(&label);
+}
+
+
void Assembler::BranchLinkOffset(Register base, int32_t offset) {
ASSERT(base != PC);
ASSERT(base != IP);
@@ -2746,7 +2783,12 @@
Register rd, int32_t value, Condition cond) {
const ARMVersion version = TargetCPUFeatures::arm_version();
if ((version == ARMv5TE) || (version == ARMv6)) {
- LoadPatchableImmediate(rd, value, cond);
+ if (constant_pool_allowed()) {
+ const int32_t offset = Array::element_offset(FindImmediate(value));
+ LoadWordFromPoolOffset(rd, offset - kHeapObjectTag);
+ } else {
+ LoadPatchableImmediate(rd, value, cond);
+ }
} else {
ASSERT(version == ARMv7);
movw(rd, Utils::Low16Bits(value), cond);
@@ -3273,6 +3315,7 @@
void Assembler::EnterDartFrame(intptr_t frame_size) {
+ ASSERT(!constant_pool_allowed());
const intptr_t offset = CodeSize();
// Save PC in frame for fast identification of corresponding code.
@@ -3301,6 +3344,7 @@
// optimized function and there may be extra space for spill slots to
// allocate. We must also set up the pool pointer for the function.
void Assembler::EnterOsrFrame(intptr_t extra_size) {
+ ASSERT(!constant_pool_allowed());
// mov(IP, Operand(PC)) loads PC + Instr::kPCReadOffset (8). This may be
// different from EntryPointToPcMarkerOffset().
const intptr_t offset =
@@ -3320,6 +3364,10 @@
void Assembler::LeaveDartFrame() {
+ // LeaveDartFrame is called from stubs (pp disallowed) and from Dart code (pp
+ // allowed), so there is no point in checking the current value of
+ // constant_pool_allowed().
+ set_constant_pool_allowed(false);
LeaveFrame((1 << PP) | (1 << FP) | (1 << LR));
// Adjust SP for PC pushed in EnterDartFrame.
AddImmediate(SP, kWordSize);
@@ -3327,6 +3375,7 @@
void Assembler::EnterStubFrame() {
+ set_constant_pool_allowed(false);
// Push 0 as saved PC for stub frames.
mov(IP, Operand(LR));
mov(LR, Operand(0));
@@ -3339,6 +3388,7 @@
void Assembler::LeaveStubFrame() {
LeaveFrame((1 << PP) | (1 << FP) | (1 << LR));
+ set_constant_pool_allowed(false);
// Adjust SP for null PC pushed in EnterStubFrame.
AddImmediate(SP, kWordSize);
}
@@ -3373,8 +3423,9 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace) {
- LoadAllocationStatsAddress(temp_reg, cid);
+ Label* trace,
+ bool inline_isolate) {
+ LoadAllocationStatsAddress(temp_reg, cid, inline_isolate);
const uword state_offset = ClassHeapStats::state_offset();
ldr(temp_reg, Address(temp_reg, state_offset));
tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
@@ -3433,29 +3484,26 @@
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cls.id(), temp_reg, failure);
- Heap* heap = Isolate::Current()->heap();
- Heap::Space space = heap->SpaceForAllocation(cls.id());
- const uword top_address = heap->TopAddress(space);
- LoadImmediate(temp_reg, top_address);
- ldr(instance_reg, Address(temp_reg));
+ MaybeTraceAllocation(cls.id(), temp_reg, failure,
+ /* inline_isolate = */ false);
+ Heap::Space space = Heap::SpaceForAllocation(cls.id());
+ ldr(temp_reg, Address(THR, Thread::heap_offset()));
+ ldr(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
// TODO(koda): Protect against unsigned overflow here.
AddImmediateSetFlags(instance_reg, instance_reg, instance_size);
// instance_reg: potential next object start.
- const uword end_address = heap->EndAddress(space);
- ASSERT(top_address < end_address);
- // Could use ldm to load (top, end), but no benefit seen experimentally.
- ldr(IP, Address(temp_reg, end_address - top_address));
+ ldr(IP, Address(temp_reg, Heap::EndOffset(space)));
cmp(IP, Operand(instance_reg));
// fail if heap end unsigned less than or equal to instance_reg.
b(failure, LS);
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
- str(instance_reg, Address(temp_reg));
+ str(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
- LoadAllocationStatsAddress(temp_reg, cls.id());
+ LoadAllocationStatsAddress(temp_reg, cls.id(),
+ /* inline_isolate = */ false);
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
@@ -3485,28 +3533,26 @@
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cid, temp1, failure);
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
- Heap::Space space = heap->SpaceForAllocation(cid);
- LoadImmediate(temp1, heap->TopAddress(space));
- ldr(instance, Address(temp1, 0)); // Potential new object start.
+ MaybeTraceAllocation(cid, temp1, failure, /* inline_isolate = */ false);
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ ldr(temp1, Address(THR, Thread::heap_offset()));
+ // Potential new object start.
+ ldr(instance, Address(temp1, Heap::TopOffset(space)));
AddImmediateSetFlags(end_address, instance, instance_size);
b(failure, CS); // Branch if unsigned overflow.
// Check if the allocation fits into the remaining space.
// instance: potential new object start.
// end_address: potential next object start.
- LoadImmediate(temp2, heap->EndAddress(space));
- ldr(temp2, Address(temp2, 0));
+ ldr(temp2, Address(temp1, Heap::EndOffset(space)));
cmp(end_address, Operand(temp2));
b(failure, CS);
- LoadAllocationStatsAddress(temp2, cid);
+ LoadAllocationStatsAddress(temp2, cid, /* inline_isolate = */ false);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- str(end_address, Address(temp1, 0));
+ str(end_address, Address(temp1, Heap::TopOffset(space)));
add(instance, instance, Operand(kHeapObjectTag));
// Initialize the tags.
@@ -3527,11 +3573,10 @@
void Assembler::Stop(const char* message) {
if (FLAG_print_stop_message) {
- StubCode* stub_code = Isolate::Current()->stub_code();
PushList((1 << R0) | (1 << IP) | (1 << LR)); // Preserve R0, IP, LR.
LoadImmediate(R0, reinterpret_cast<int32_t>(message));
// PrintStopMessage() preserves all registers.
- BranchLink(&stub_code->PrintStopMessageLabel()); // Passing message in R0.
+ BranchLink(&StubCode::PrintStopMessage_entry()->label());
PopList((1 << R0) | (1 << IP) | (1 << LR)); // Restore R0, IP, LR.
}
// Emit the message address before the svc instruction, so that we can
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 70dd9ad..8218bb9 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -21,6 +21,7 @@
// Forward declarations.
class RuntimeEntry;
+class StubEntry;
class Label : public ValueObject {
public:
@@ -319,7 +320,7 @@
prologue_offset_(-1),
use_far_branches_(use_far_branches),
comments_(),
- allow_constant_pool_(true) { }
+ constant_pool_allowed_(false) { }
~Assembler() { }
@@ -608,17 +609,22 @@
// Macros.
// Branch to an entry address. Call sequence is never patched.
void Branch(const ExternalLabel* label, Condition cond = AL);
+ void Branch(const StubEntry& stub_entry, Condition cond = AL);
// Branch to an entry address. Call sequence can be patched or even replaced.
void BranchPatchable(const ExternalLabel* label);
+ void BranchPatchable(const StubEntry& stub_entry);
// Branch and link to an entry address. Call sequence is never patched.
void BranchLink(const ExternalLabel* label);
+ void BranchLink(const StubEntry& stub_entry);
void BranchLink(const ExternalLabel* label, Patchability patchable);
+ void BranchLink(const StubEntry& stub_entry, Patchability patchable);
// Branch and link to an entry address. Call sequence can be patched.
void BranchLinkPatchable(const ExternalLabel* label);
+ void BranchLinkPatchable(const StubEntry& stub_entry);
// Branch and link to [base + offset]. Call sequence is never patched.
void BranchLinkOffset(Register base, int32_t offset);
@@ -755,6 +761,7 @@
Register scratch2,
Label* miss);
+ intptr_t FindImmediate(int32_t imm);
void LoadWordFromPoolOffset(Register rd, int32_t offset, Condition cond = AL);
void LoadFromOffset(OperandSize type,
Register reg,
@@ -938,7 +945,8 @@
// which will allocate in the runtime where tracing occurs.
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace);
+ Label* trace,
+ bool inline_isolate = true);
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
@@ -965,11 +973,11 @@
static bool IsSafe(const Object& object) { return true; }
static bool IsSafeSmi(const Object& object) { return object.IsSmi(); }
- bool allow_constant_pool() const {
- return allow_constant_pool_;
+ bool constant_pool_allowed() const {
+ return constant_pool_allowed_;
}
- void set_allow_constant_pool(bool b) {
- allow_constant_pool_ = b;
+ void set_constant_pool_allowed(bool b) {
+ constant_pool_allowed_ = b;
}
private:
@@ -1005,7 +1013,7 @@
GrowableArray<CodeComment*> comments_;
- bool allow_constant_pool_;
+ bool constant_pool_allowed_;
void LoadObjectHelper(Register rd,
const Object& object,
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 290890e..11fbdb2 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -30,7 +30,7 @@
prologue_offset_(-1),
use_far_branches_(use_far_branches),
comments_(),
- allow_constant_pool_(true) {
+ constant_pool_allowed_(false) {
}
@@ -316,21 +316,22 @@
// because the offset wouldn't be aligned, it would be only one instruction
// for the first 64 entries.
sub(pp, pp, Operand(kHeapObjectTag));
+ set_constant_pool_allowed(pp == PP);
}
-void Assembler::LoadWordFromPoolOffset(Register dst, Register pp,
- uint32_t offset) {
- ASSERT(dst != pp);
+void Assembler::LoadWordFromPoolOffset(Register dst, uint32_t offset) {
+ ASSERT(constant_pool_allowed());
+ ASSERT(dst != PP);
Operand op;
const uint32_t upper20 = offset & 0xfffff000;
if (Address::CanHoldOffset(offset)) {
- ldr(dst, Address(pp, offset));
+ ldr(dst, Address(PP, offset));
} else if (Operand::CanHold(upper20, kXRegSizeInBits, &op) ==
Operand::Immediate) {
const uint32_t lower12 = offset & 0x00000fff;
ASSERT(Address::CanHoldOffset(lower12));
- add(dst, pp, op);
+ add(dst, PP, op);
ldr(dst, Address(dst, lower12));
} else {
const uint16_t offset_low = Utils::Low16Bits(offset);
@@ -339,14 +340,14 @@
if (offset_high != 0) {
movk(dst, Immediate(offset_high), 1);
}
- ldr(dst, Address(pp, dst));
+ ldr(dst, Address(PP, dst));
}
}
-void Assembler::LoadWordFromPoolOffsetFixed(Register dst, Register pp,
- uint32_t offset) {
- ASSERT(dst != pp);
+void Assembler::LoadWordFromPoolOffsetFixed(Register dst, uint32_t offset) {
+ ASSERT(constant_pool_allowed());
+ ASSERT(dst != PP);
Operand op;
const uint32_t upper20 = offset & 0xfffff000;
const uint32_t lower12 = offset & 0x00000fff;
@@ -354,7 +355,7 @@
Operand::CanHold(upper20, kXRegSizeInBits, &op);
ASSERT(ot == Operand::Immediate);
ASSERT(Address::CanHoldOffset(lower12));
- add(dst, pp, op);
+ add(dst, PP, op);
ldr(dst, Address(dst, lower12));
}
@@ -366,7 +367,7 @@
bool Assembler::CanLoadFromObjectPool(const Object& object) const {
ASSERT(!Thread::CanLoadFromThread(object));
- if (!allow_constant_pool()) {
+ if (!constant_pool_allowed()) {
return false;
}
@@ -383,36 +384,24 @@
}
-bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) {
- if (!allow_constant_pool()) {
- return false;
- }
- return !Utils::IsInt(32, imm) && (pp != kNoPP);
-}
-
-
-void Assembler::LoadExternalLabel(Register dst,
- const ExternalLabel* label,
- Patchability patchable,
- Register pp) {
- const int64_t target = static_cast<int64_t>(label->address());
- if (CanLoadImmediateFromPool(target, pp)) {
+void Assembler::LoadExternalLabel(Register dst, const ExternalLabel* label) {
+ if (constant_pool_allowed()) {
const int32_t offset = ObjectPool::element_offset(
- object_pool_wrapper_.FindExternalLabel(label, patchable));
- LoadWordFromPoolOffset(dst, pp, offset);
+ object_pool_wrapper_.FindExternalLabel(label, kNotPatchable));
+ LoadWordFromPoolOffset(dst, offset);
} else {
- LoadImmediate(dst, target, kNoPP);
+ const int64_t target = static_cast<int64_t>(label->address());
+ LoadImmediate(dst, target);
}
}
void Assembler::LoadExternalLabelFixed(Register dst,
const ExternalLabel* label,
- Patchability patchable,
- Register pp) {
+ Patchability patchable) {
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, patchable));
- LoadWordFromPoolOffsetFixed(dst, pp, offset);
+ LoadWordFromPoolOffsetFixed(dst, offset);
}
@@ -423,7 +412,6 @@
void Assembler::LoadObjectHelper(Register dst,
const Object& object,
- Register pp,
bool is_unique) {
if (Thread::CanLoadFromThread(object)) {
ldr(dst, Address(THR, Thread::OffsetFromThread(object)));
@@ -431,43 +419,53 @@
const int32_t offset = ObjectPool::element_offset(
is_unique ? object_pool_wrapper_.AddObject(object)
: object_pool_wrapper_.FindObject(object));
- LoadWordFromPoolOffset(dst, pp, offset);
+ LoadWordFromPoolOffset(dst, offset);
} else {
ASSERT(object.IsSmi() || object.InVMHeap());
- LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()), pp);
+ LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()));
}
}
-void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
- LoadObjectHelper(dst, object, pp, false);
+void Assembler::LoadFunctionFromCalleePool(Register dst,
+ const Function& function,
+ Register new_pp) {
+ ASSERT(!constant_pool_allowed());
+ ASSERT(new_pp != PP);
+ const int32_t offset =
+ ObjectPool::element_offset(object_pool_wrapper_.FindObject(function));
+ ASSERT(Address::CanHoldOffset(offset));
+ ldr(dst, Address(new_pp, offset));
}
-void Assembler::LoadUniqueObject(Register dst,
- const Object& object,
- Register pp) {
- LoadObjectHelper(dst, object, pp, true);
+void Assembler::LoadObject(Register dst, const Object& object) {
+ LoadObjectHelper(dst, object, false);
}
-void Assembler::CompareObject(Register reg, const Object& object, Register pp) {
+void Assembler::LoadUniqueObject(Register dst, const Object& object) {
+ LoadObjectHelper(dst, object, true);
+}
+
+
+void Assembler::CompareObject(Register reg, const Object& object) {
if (Thread::CanLoadFromThread(object)) {
ldr(TMP, Address(THR, Thread::OffsetFromThread(object)));
CompareRegisters(reg, TMP);
} else if (CanLoadFromObjectPool(object)) {
- LoadObject(TMP, object, pp);
+ LoadObject(TMP, object);
CompareRegisters(reg, TMP);
} else {
- CompareImmediate(reg, reinterpret_cast<int64_t>(object.raw()), pp);
+ CompareImmediate(reg, reinterpret_cast<int64_t>(object.raw()));
}
}
-void Assembler::LoadDecodableImmediate(Register reg, int64_t imm, Register pp) {
- if ((pp != kNoPP) && allow_constant_pool()) {
+void Assembler::LoadDecodableImmediate(Register reg, int64_t imm) {
+ if (constant_pool_allowed()) {
const int32_t offset = ObjectPool::element_offset(FindImmediate(imm));
- LoadWordFromPoolOffset(reg, pp, offset);
+ LoadWordFromPoolOffset(reg, offset);
} else {
// TODO(zra): Since this sequence only needs to be decodable, it can be
// of variable length.
@@ -490,111 +488,127 @@
}
-void Assembler::LoadImmediate(Register reg, int64_t imm, Register pp) {
+void Assembler::LoadImmediate(Register reg, int64_t imm) {
Comment("LoadImmediate");
- if (CanLoadImmediateFromPool(imm, pp)) {
- // It's a 64-bit constant and we're not in the VM isolate, so load from
- // object pool.
- // Save the bits that must be masked-off for the SmiTag
- int64_t val_smi_tag = imm & kSmiTagMask;
- imm &= ~kSmiTagMask; // Mask off the tag bits.
+ // Is it 0?
+ if (imm == 0) {
+ movz(reg, Immediate(0), 0);
+ return;
+ }
+
+ // Can we use one orri operation?
+ Operand op;
+ Operand::OperandType ot;
+ ot = Operand::CanHold(imm, kXRegSizeInBits, &op);
+ if (ot == Operand::BitfieldImm) {
+ orri(reg, ZR, Immediate(imm));
+ return;
+ }
+
+ // We may fall back on movz, movk, movn.
+ const uint32_t w0 = Utils::Low32Bits(imm);
+ const uint32_t w1 = Utils::High32Bits(imm);
+ const uint16_t h0 = Utils::Low16Bits(w0);
+ const uint16_t h1 = Utils::High16Bits(w0);
+ const uint16_t h2 = Utils::Low16Bits(w1);
+ const uint16_t h3 = Utils::High16Bits(w1);
+
+ // Special case for w1 == 0xffffffff
+ if (w1 == 0xffffffff) {
+ if (h1 == 0xffff) {
+ movn(reg, Immediate(~h0), 0);
+ } else {
+ movn(reg, Immediate(~h1), 1);
+ movk(reg, Immediate(h0), 0);
+ }
+ return;
+ }
+
+ // Special case for h3 == 0xffff
+ if (h3 == 0xffff) {
+ // We know h2 != 0xffff.
+ movn(reg, Immediate(~h2), 2);
+ if (h1 != 0xffff) {
+ movk(reg, Immediate(h1), 1);
+ }
+ if (h0 != 0xffff) {
+ movk(reg, Immediate(h0), 0);
+ }
+ return;
+ }
+
+ // Use constant pool if allowed, unless we can load imm with 2 instructions.
+ if ((w1 != 0) && constant_pool_allowed()) {
const int32_t offset = ObjectPool::element_offset(FindImmediate(imm));
- LoadWordFromPoolOffset(reg, pp, offset);
- if (val_smi_tag != 0) {
- // Add back the tag bits.
- orri(reg, reg, Immediate(val_smi_tag));
- }
- } else {
- // 0. Is it 0?
- if (imm == 0) {
- movz(reg, Immediate(0), 0);
- return;
- }
+ LoadWordFromPoolOffset(reg, offset);
+ return;
+ }
- // 1. Can we use one orri operation?
- Operand op;
- Operand::OperandType ot;
- ot = Operand::CanHold(imm, kXRegSizeInBits, &op);
- if (ot == Operand::BitfieldImm) {
- orri(reg, ZR, Immediate(imm));
- return;
- }
-
- // 2. Fall back on movz, movk, movn.
- const uint32_t w0 = Utils::Low32Bits(imm);
- const uint32_t w1 = Utils::High32Bits(imm);
- const uint16_t h0 = Utils::Low16Bits(w0);
- const uint16_t h1 = Utils::High16Bits(w0);
- const uint16_t h2 = Utils::Low16Bits(w1);
- const uint16_t h3 = Utils::High16Bits(w1);
-
- // Special case for w1 == 0xffffffff
- if (w1 == 0xffffffff) {
- if (h1 == 0xffff) {
- movn(reg, Immediate(~h0), 0);
- } else {
- movn(reg, Immediate(~h1), 1);
- movk(reg, Immediate(h0), 0);
- }
- return;
- }
-
- // Special case for h3 == 0xffff
- if (h3 == 0xffff) {
- // We know h2 != 0xffff.
- movn(reg, Immediate(~h2), 2);
- if (h1 != 0xffff) {
- movk(reg, Immediate(h1), 1);
- }
- if (h0 != 0xffff) {
- movk(reg, Immediate(h0), 0);
- }
- return;
- }
-
- bool initialized = false;
- if (h0 != 0) {
- movz(reg, Immediate(h0), 0);
+ bool initialized = false;
+ if (h0 != 0) {
+ movz(reg, Immediate(h0), 0);
+ initialized = true;
+ }
+ if (h1 != 0) {
+ if (initialized) {
+ movk(reg, Immediate(h1), 1);
+ } else {
+ movz(reg, Immediate(h1), 1);
initialized = true;
}
- if (h1 != 0) {
- if (initialized) {
- movk(reg, Immediate(h1), 1);
- } else {
- movz(reg, Immediate(h1), 1);
- initialized = true;
- }
+ }
+ if (h2 != 0) {
+ if (initialized) {
+ movk(reg, Immediate(h2), 2);
+ } else {
+ movz(reg, Immediate(h2), 2);
+ initialized = true;
}
- if (h2 != 0) {
- if (initialized) {
- movk(reg, Immediate(h2), 2);
- } else {
- movz(reg, Immediate(h2), 2);
- initialized = true;
- }
- }
- if (h3 != 0) {
- if (initialized) {
- movk(reg, Immediate(h3), 3);
- } else {
- movz(reg, Immediate(h3), 3);
- }
+ }
+ if (h3 != 0) {
+ if (initialized) {
+ movk(reg, Immediate(h3), 3);
+ } else {
+ movz(reg, Immediate(h3), 3);
}
}
}
-void Assembler::LoadDImmediate(VRegister vd, double immd, Register pp) {
+void Assembler::LoadDImmediate(VRegister vd, double immd) {
if (!fmovdi(vd, immd)) {
int64_t imm = bit_cast<int64_t, double>(immd);
- LoadImmediate(TMP, imm, pp);
+ LoadImmediate(TMP, imm);
fmovdr(vd, TMP);
}
}
-void Assembler::AddImmediate(
- Register dest, Register rn, int64_t imm, Register pp) {
+void Assembler::Branch(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ Branch(&label);
+}
+
+
+void Assembler::BranchPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchPatchable(&label);
+}
+
+
+void Assembler::BranchLink(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLink(&label);
+}
+
+
+void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLinkPatchable(&label);
+}
+
+
+void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) {
Operand op;
if (imm == 0) {
if (dest != rn) {
@@ -610,14 +624,13 @@
} else {
// TODO(zra): Try adding top 12 bits, then bottom 12 bits.
ASSERT(rn != TMP2);
- LoadImmediate(TMP2, imm, pp);
+ LoadImmediate(TMP2, imm);
add(dest, rn, Operand(TMP2));
}
}
-void Assembler::AddImmediateSetFlags(
- Register dest, Register rn, int64_t imm, Register pp) {
+void Assembler::AddImmediateSetFlags(Register dest, Register rn, int64_t imm) {
Operand op;
if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
// Handles imm == kMinInt64.
@@ -629,14 +642,13 @@
} else {
// TODO(zra): Try adding top 12 bits, then bottom 12 bits.
ASSERT(rn != TMP2);
- LoadImmediate(TMP2, imm, pp);
+ LoadImmediate(TMP2, imm);
adds(dest, rn, Operand(TMP2));
}
}
-void Assembler::SubImmediateSetFlags(
- Register dest, Register rn, int64_t imm, Register pp) {
+void Assembler::SubImmediateSetFlags(Register dest, Register rn, int64_t imm) {
Operand op;
if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
// Handles imm == kMinInt64.
@@ -648,60 +660,57 @@
} else {
// TODO(zra): Try subtracting top 12 bits, then bottom 12 bits.
ASSERT(rn != TMP2);
- LoadImmediate(TMP2, imm, pp);
+ LoadImmediate(TMP2, imm);
subs(dest, rn, Operand(TMP2));
}
}
-void Assembler::AndImmediate(
- Register rd, Register rn, int64_t imm, Register pp) {
+void Assembler::AndImmediate(Register rd, Register rn, int64_t imm) {
Operand imm_op;
if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
andi(rd, rn, Immediate(imm));
} else {
- LoadImmediate(TMP, imm, pp);
+ LoadImmediate(TMP, imm);
and_(rd, rn, Operand(TMP));
}
}
-void Assembler::OrImmediate(
- Register rd, Register rn, int64_t imm, Register pp) {
+void Assembler::OrImmediate(Register rd, Register rn, int64_t imm) {
Operand imm_op;
if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
orri(rd, rn, Immediate(imm));
} else {
- LoadImmediate(TMP, imm, pp);
+ LoadImmediate(TMP, imm);
orr(rd, rn, Operand(TMP));
}
}
-void Assembler::XorImmediate(
- Register rd, Register rn, int64_t imm, Register pp) {
+void Assembler::XorImmediate(Register rd, Register rn, int64_t imm) {
Operand imm_op;
if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
eori(rd, rn, Immediate(imm));
} else {
- LoadImmediate(TMP, imm, pp);
+ LoadImmediate(TMP, imm);
eor(rd, rn, Operand(TMP));
}
}
-void Assembler::TestImmediate(Register rn, int64_t imm, Register pp) {
+void Assembler::TestImmediate(Register rn, int64_t imm) {
Operand imm_op;
if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
tsti(rn, Immediate(imm));
} else {
- LoadImmediate(TMP, imm, pp);
+ LoadImmediate(TMP, imm);
tst(rn, Operand(TMP));
}
}
-void Assembler::CompareImmediate(Register rn, int64_t imm, Register pp) {
+void Assembler::CompareImmediate(Register rn, int64_t imm) {
Operand op;
if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
cmp(rn, op);
@@ -710,80 +719,76 @@
cmn(rn, op);
} else {
ASSERT(rn != TMP2);
- LoadImmediate(TMP2, imm, pp);
+ LoadImmediate(TMP2, imm);
cmp(rn, Operand(TMP2));
}
}
void Assembler::LoadFromOffset(
- Register dest, Register base, int32_t offset, Register pp, OperandSize sz) {
+ Register dest, Register base, int32_t offset, OperandSize sz) {
if (Address::CanHoldOffset(offset, Address::Offset, sz)) {
ldr(dest, Address(base, offset, Address::Offset, sz), sz);
} else {
ASSERT(base != TMP2);
- AddImmediate(TMP2, base, offset, pp);
+ AddImmediate(TMP2, base, offset);
ldr(dest, Address(TMP2), sz);
}
}
-void Assembler::LoadDFromOffset(
- VRegister dest, Register base, int32_t offset, Register pp) {
+void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) {
if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) {
fldrd(dest, Address(base, offset, Address::Offset, kDWord));
} else {
ASSERT(base != TMP2);
- AddImmediate(TMP2, base, offset, pp);
+ AddImmediate(TMP2, base, offset);
fldrd(dest, Address(TMP2));
}
}
-void Assembler::LoadQFromOffset(
- VRegister dest, Register base, int32_t offset, Register pp) {
+void Assembler::LoadQFromOffset(VRegister dest, Register base, int32_t offset) {
if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) {
fldrq(dest, Address(base, offset, Address::Offset, kQWord));
} else {
ASSERT(base != TMP2);
- AddImmediate(TMP2, base, offset, pp);
+ AddImmediate(TMP2, base, offset);
fldrq(dest, Address(TMP2));
}
}
void Assembler::StoreToOffset(
- Register src, Register base, int32_t offset, Register pp, OperandSize sz) {
+ Register src, Register base, int32_t offset, OperandSize sz) {
ASSERT(base != TMP2);
if (Address::CanHoldOffset(offset, Address::Offset, sz)) {
str(src, Address(base, offset, Address::Offset, sz), sz);
} else {
ASSERT(src != TMP2);
- AddImmediate(TMP2, base, offset, pp);
+ AddImmediate(TMP2, base, offset);
str(src, Address(TMP2), sz);
}
}
-void Assembler::StoreDToOffset(
- VRegister src, Register base, int32_t offset, Register pp) {
+void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) {
if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) {
fstrd(src, Address(base, offset, Address::Offset, kDWord));
} else {
ASSERT(base != TMP2);
- AddImmediate(TMP2, base, offset, pp);
+ AddImmediate(TMP2, base, offset);
fstrd(src, Address(TMP2));
}
}
-void Assembler::StoreQToOffset(
- VRegister src, Register base, int32_t offset, Register pp) {
+void Assembler::StoreQToOffset(VRegister src, Register base, int32_t offset) {
if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) {
fstrq(src, Address(base, offset, Address::Offset, kQWord));
} else {
ASSERT(base != TMP2);
- AddImmediate(TMP2, base, offset, pp);
+ AddImmediate(TMP2, base, offset);
fstrq(src, Address(TMP2));
}
}
@@ -857,13 +862,12 @@
void Assembler::StoreIntoObjectOffset(Register object,
int32_t offset,
Register value,
- Register pp,
bool can_value_be_smi) {
if (Address::CanHoldOffset(offset - kHeapObjectTag)) {
StoreIntoObject(
object, FieldAddress(object, offset), value, can_value_be_smi);
} else {
- AddImmediate(TMP, object, offset - kHeapObjectTag, pp);
+ AddImmediate(TMP, object, offset - kHeapObjectTag);
StoreIntoObject(object, Address(TMP), value, can_value_be_smi);
}
}
@@ -917,12 +921,11 @@
void Assembler::StoreIntoObjectOffsetNoBarrier(Register object,
int32_t offset,
- Register value,
- Register pp) {
+ Register value) {
if (Address::CanHoldOffset(offset - kHeapObjectTag)) {
StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value);
} else {
- AddImmediate(TMP, object, offset - kHeapObjectTag, pp);
+ AddImmediate(TMP, object, offset - kHeapObjectTag);
StoreIntoObjectNoBarrier(object, Address(TMP), value);
}
}
@@ -934,71 +937,69 @@
ASSERT(value.IsSmi() || value.InVMHeap() ||
(value.IsOld() && value.IsNotTemporaryScopedHandle()));
// No store buffer update.
- LoadObject(TMP2, value, PP);
+ LoadObject(TMP2, value);
str(TMP2, dest);
}
void Assembler::StoreIntoObjectOffsetNoBarrier(Register object,
int32_t offset,
- const Object& value,
- Register pp) {
+ const Object& value) {
if (Address::CanHoldOffset(offset - kHeapObjectTag)) {
StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value);
} else {
- AddImmediate(TMP, object, offset - kHeapObjectTag, pp);
+ AddImmediate(TMP, object, offset - kHeapObjectTag);
StoreIntoObjectNoBarrier(object, Address(TMP), value);
}
}
-void Assembler::LoadClassId(Register result, Register object, Register pp) {
+void Assembler::LoadClassId(Register result, Register object) {
ASSERT(RawObject::kClassIdTagPos == kBitsPerInt32);
ASSERT(RawObject::kClassIdTagSize == kBitsPerInt32);
const intptr_t class_id_offset = Object::tags_offset() +
RawObject::kClassIdTagPos / kBitsPerByte;
- LoadFromOffset(result, object, class_id_offset - kHeapObjectTag, pp,
+ LoadFromOffset(result, object, class_id_offset - kHeapObjectTag,
kUnsignedWord);
}
-void Assembler::LoadClassById(Register result, Register class_id, Register pp) {
+void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
LoadIsolate(result);
const intptr_t offset =
Isolate::class_table_offset() + ClassTable::table_offset();
- LoadFromOffset(result, result, offset, pp);
+ LoadFromOffset(result, result, offset);
ldr(result, Address(result, class_id, UXTX, Address::Scaled));
}
-void Assembler::LoadClass(Register result, Register object, Register pp) {
+void Assembler::LoadClass(Register result, Register object) {
ASSERT(object != TMP);
- LoadClassId(TMP, object, pp);
- LoadClassById(result, TMP, pp);
+ LoadClassId(TMP, object);
+ LoadClassById(result, TMP);
}
-void Assembler::CompareClassId(
- Register object, intptr_t class_id, Register pp) {
- LoadClassId(TMP, object, pp);
- CompareImmediate(TMP, class_id, pp);
+void Assembler::CompareClassId(Register object, intptr_t class_id) {
+ LoadClassId(TMP, object);
+ CompareImmediate(TMP, class_id);
}
void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
// Load up a null object. We only need it so we can use LoadClassId on it in
// the case that object is a Smi..
- LoadObject(TMP, Object::null_object(), PP);
+ LoadObject(TMP, Object::null_object());
// Check if the object is a Smi.
tsti(object, Immediate(kSmiTagMask));
// If the object *is* a Smi, use the null object instead. o/w leave alone.
csel(TMP, TMP, object, EQ);
// Loads either the cid of the object if it isn't a Smi, or the cid of null
// if it is a Smi, which will be ignored.
- LoadClassId(result, TMP, PP);
+ LoadClassId(result, TMP);
- LoadImmediate(TMP, kSmiCid, PP);
+ LoadImmediate(TMP, kSmiCid);
// If object is a Smi, move the Smi cid into result. o/w leave alone.
csel(result, TMP, result, EQ);
}
@@ -1020,22 +1021,22 @@
b(¬_smi, NE);
AsrImmediate(scratch, value, 32);
- LoadImmediate(result, ICData::kUint32RangeBit, PP);
+ LoadImmediate(result, ICData::kUint32RangeBit);
cmp(scratch, Operand(1));
b(&done, EQ);
neg(scratch, scratch);
add(result, scratch, Operand(ICData::kInt32RangeBit));
cmp(scratch, Operand(1));
- LoadImmediate(TMP, ICData::kSignedRangeBit, PP);
+ LoadImmediate(TMP, ICData::kSignedRangeBit);
csel(result, result, TMP, LS);
b(&done);
Bind(¬_smi);
- CompareClassId(value, kMintCid, PP);
+ CompareClassId(value, kMintCid);
b(not_mint, NE);
- LoadImmediate(result, ICData::kInt64RangeBit, PP);
+ LoadImmediate(result, ICData::kInt64RangeBit);
Bind(&done);
}
@@ -1061,7 +1062,7 @@
// Reserve space for arguments and align frame before entering
// the C++ world.
if (frame_space != 0) {
- AddImmediate(SP, SP, -frame_space, kNoPP);
+ AddImmediate(SP, SP, -frame_space);
}
if (OS::ActivationFrameAlignment() > 1) {
andi(SP, SP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
@@ -1086,37 +1087,40 @@
void Assembler::EnterDartFrame(intptr_t frame_size) {
+ ASSERT(!constant_pool_allowed());
// Setup the frame.
adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker.
EnterFrame(0);
TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker.
// Load the pool pointer.
- LoadPoolPointer(PP);
+ LoadPoolPointer();
// Reserve space.
if (frame_size > 0) {
- AddImmediate(SP, SP, -frame_size, PP);
+ AddImmediate(SP, SP, -frame_size);
}
}
void Assembler::EnterDartFrameWithInfo(intptr_t frame_size, Register new_pp) {
+ ASSERT(!constant_pool_allowed());
// Setup the frame.
adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker.
EnterFrame(0);
TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker.
// Load the pool pointer.
- if (new_pp == kNoPP) {
- LoadPoolPointer(PP);
+ if (new_pp == kNoRegister) {
+ LoadPoolPointer();
} else {
mov(PP, new_pp);
+ set_constant_pool_allowed(true);
}
// Reserve space.
if (frame_size > 0) {
- AddImmediate(SP, SP, -frame_size, PP);
+ AddImmediate(SP, SP, -frame_size);
}
}
@@ -1127,27 +1131,33 @@
// optimized function and there may be extra space for spill slots to
// allocate. We must also set up the pool pointer for the function.
void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) {
+ ASSERT(!constant_pool_allowed());
Comment("EnterOsrFrame");
adr(TMP, Immediate(-CodeSize()));
- StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize, kNoPP);
+ StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize);
// Setup pool pointer for this dart function.
- if (new_pp == kNoPP) {
- LoadPoolPointer(PP);
+ if (new_pp == kNoRegister) {
+ LoadPoolPointer();
} else {
mov(PP, new_pp);
+ set_constant_pool_allowed(true);
}
if (extra_size > 0) {
- AddImmediate(SP, SP, -extra_size, PP);
+ AddImmediate(SP, SP, -extra_size);
}
}
void Assembler::LeaveDartFrame() {
+ // LeaveDartFrame is called from stubs (pp disallowed) and from Dart code (pp
+ // allowed), so there is no point in checking the current value of
+ // constant_pool_allowed().
+ set_constant_pool_allowed(false);
// Restore and untag PP.
- LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize, kNoPP);
+ LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize);
sub(PP, PP, Operand(kHeapObjectTag));
LeaveFrame();
}
@@ -1185,7 +1195,7 @@
const intptr_t kPushedRegistersSize =
kDartVolatileCpuRegCount * kWordSize +
kDartVolatileFpuRegCount * kWordSize;
- AddImmediate(SP, FP, -kPushedRegistersSize, PP);
+ AddImmediate(SP, FP, -kPushedRegistersSize);
for (int i = kDartLastVolatileCpuReg; i >= kDartFirstVolatileCpuReg; i--) {
const Register reg = static_cast<Register>(i);
Pop(reg);
@@ -1213,23 +1223,24 @@
void Assembler::EnterStubFrame() {
+ set_constant_pool_allowed(false);
EnterFrame(0);
// Save caller's pool pointer. Push 0 in the saved PC area for stub frames.
TagAndPushPPAndPcMarker(ZR);
- LoadPoolPointer(PP);
+ LoadPoolPointer();
}
void Assembler::LeaveStubFrame() {
+ set_constant_pool_allowed(false);
// Restore and untag PP.
- LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize, kNoPP);
+ LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize);
sub(PP, PP, Operand(kHeapObjectTag));
LeaveFrame();
}
void Assembler::UpdateAllocationStats(intptr_t cid,
- Register pp,
Heap::Space space,
bool inline_isolate) {
ASSERT(cid > 0);
@@ -1240,28 +1251,27 @@
ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
if (cid < kNumPredefinedCids) {
LoadImmediate(
- TMP2, reinterpret_cast<uword>(*table_ptr) + counter_offset, pp);
+ TMP2, reinterpret_cast<uword>(*table_ptr) + counter_offset);
} else {
- LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr), pp);
+ LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr));
ldr(TMP, Address(TMP2));
- AddImmediate(TMP2, TMP, counter_offset, pp);
+ 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, pp);
+ AddImmediate(TMP2, TMP, counter_offset);
}
ldr(TMP, Address(TMP2, 0));
- AddImmediate(TMP, TMP, 1, pp);
+ AddImmediate(TMP, TMP, 1);
str(TMP, Address(TMP2, 0));
}
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
- Register pp,
Heap::Space space,
bool inline_isolate) {
ASSERT(cid > 0);
@@ -1277,21 +1287,21 @@
ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
if (cid < kNumPredefinedCids) {
LoadImmediate(TMP2,
- reinterpret_cast<uword>(*table_ptr) + class_offset, pp);
+ reinterpret_cast<uword>(*table_ptr) + class_offset);
} else {
- LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr), pp);
+ LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr));
ldr(TMP, Address(TMP2));
- AddImmediate(TMP2, TMP, class_offset, pp);
+ 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, pp);
+ AddImmediate(TMP2, TMP, class_offset);
}
ldr(TMP, Address(TMP2, count_field_offset));
- AddImmediate(TMP, TMP, 1, pp);
+ AddImmediate(TMP, TMP, 1);
str(TMP, Address(TMP2, count_field_offset));
ldr(TMP, Address(TMP2, size_field_offset));
add(TMP, TMP, Operand(size_reg));
@@ -1301,21 +1311,27 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Register pp,
- Label* trace) {
+ Label* trace,
+ bool inline_isolate) {
ASSERT(cid > 0);
- intptr_t state_offset;
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr =
- class_table->StateAddressFor(cid, &state_offset);
-
- if (cid < kNumPredefinedCids) {
- LoadImmediate(
- temp_reg, reinterpret_cast<uword>(*table_ptr) + state_offset, pp);
+ 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) {
+ 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 {
- LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr), pp);
- ldr(temp_reg, Address(temp_reg, 0));
- AddImmediate(temp_reg, temp_reg, state_offset, pp);
+ 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()));
@@ -1326,47 +1342,42 @@
void Assembler::TryAllocate(const Class& cls,
Label* failure,
Register instance_reg,
- Register temp_reg,
- Register pp) {
+ Register temp_reg) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cls.id(), temp_reg, pp, failure);
+ MaybeTraceAllocation(cls.id(), temp_reg, failure,
+ /* inline_isolate = */ false);
const intptr_t instance_size = cls.instance_size();
- Heap* heap = Isolate::Current()->heap();
- Heap::Space space = heap->SpaceForAllocation(cls.id());
- const uword top_address = heap->TopAddress(space);
- LoadImmediate(temp_reg, top_address, pp);
- ldr(instance_reg, Address(temp_reg));
+ Heap::Space space = Heap::SpaceForAllocation(cls.id());
+ ldr(temp_reg, Address(THR, Thread::heap_offset()));
+ ldr(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
// TODO(koda): Protect against unsigned overflow here.
- AddImmediateSetFlags(instance_reg, instance_reg, instance_size, pp);
+ AddImmediateSetFlags(instance_reg, instance_reg, instance_size);
// instance_reg: potential next object start.
- const uword end_address = heap->EndAddress(space);
- ASSERT(top_address < end_address);
- // Could use ldm to load (top, end), but no benefit seen experimentally.
- ldr(TMP, Address(temp_reg, end_address - top_address));
+ ldr(TMP, Address(temp_reg, Heap::EndOffset(space)));
CompareRegisters(TMP, instance_reg);
// fail if heap end unsigned less than or equal to instance_reg.
b(failure, LS);
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
- str(instance_reg, Address(temp_reg));
+ str(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(
- instance_reg, instance_reg, -instance_size + kHeapObjectTag, pp);
- UpdateAllocationStats(cls.id(), pp, space);
+ instance_reg, instance_reg, -instance_size + kHeapObjectTag);
+ UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
uword tags = 0;
tags = RawObject::SizeTag::update(instance_size, tags);
ASSERT(cls.id() != kIllegalCid);
tags = RawObject::ClassIdTag::update(cls.id(), tags);
- LoadImmediate(TMP, tags, pp);
- StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp);
+ LoadImmediate(TMP, tags);
+ StoreFieldToOffset(TMP, instance_reg, Object::tags_offset());
} else {
b(failure);
}
@@ -1384,36 +1395,35 @@
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cid, temp1, PP, failure);
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
- Heap::Space space = heap->SpaceForAllocation(cid);
- LoadImmediate(temp1, heap->TopAddress(space), PP);
- ldr(instance, Address(temp1, 0)); // Potential new object start.
- AddImmediateSetFlags(end_address, instance, instance_size, PP);
+ MaybeTraceAllocation(cid, temp1, failure, /* inline_isolate = */ false);
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ ldr(temp1, Address(THR, Thread::heap_offset()));
+ // Potential new object start.
+ ldr(instance, Address(temp1, Heap::TopOffset(space)));
+ AddImmediateSetFlags(end_address, instance, instance_size);
b(failure, CS); // Fail on unsigned overflow.
// Check if the allocation fits into the remaining space.
// instance: potential new object start.
// end_address: potential next object start.
- LoadImmediate(temp2, heap->EndAddress(space), PP);
- ldr(temp2, Address(temp2, 0));
+ ldr(temp2, Address(temp1, Heap::EndOffset(space)));
cmp(end_address, Operand(temp2));
b(failure, CS);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- str(end_address, Address(temp1, 0));
+ str(end_address, Address(temp1, Heap::TopOffset(space)));
add(instance, instance, Operand(kHeapObjectTag));
- LoadImmediate(temp2, instance_size, PP);
- UpdateAllocationStatsWithSize(cid, temp2, PP, space);
+ LoadImmediate(temp2, instance_size);
+ UpdateAllocationStatsWithSize(cid, temp2, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// instance: new object start as a tagged pointer.
uword tags = 0;
tags = RawObject::ClassIdTag::update(cid, tags);
tags = RawObject::SizeTag::update(instance_size, tags);
- LoadImmediate(temp2, tags, PP);
+ LoadImmediate(temp2, tags);
str(temp2, FieldAddress(instance, Array::tags_offset())); // Store tags.
} else {
b(failure);
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index 32da483..936e105 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -21,6 +21,7 @@
// Forward declarations.
class RuntimeEntry;
+class StubEntry;
class Immediate : public ValueObject {
public:
@@ -119,7 +120,7 @@
// is unscaled.
Address(Register rn, int32_t offset = 0, AddressType at = Offset,
OperandSize sz = kDoubleWord) {
- ASSERT((rn != R31) && (rn != ZR));
+ ASSERT((rn != kNoRegister) && (rn != R31) && (rn != ZR));
ASSERT(CanHoldOffset(offset, at, sz));
const Register crn = ConcreteRegister(rn);
const int32_t scale = Log2OperandSizeBytes(sz);
@@ -1161,6 +1162,8 @@
void PopAndUntagPP() {
ldr(PP, Address(SP, 1 * kWordSize, Address::PostIndex));
sub(PP, PP, Operand(kHeapObjectTag));
+ // The caller of PopAndUntagPP() must explicitly allow use of popped PP.
+ set_constant_pool_allowed(false);
}
void tst(Register rn, Operand o) {
ands(ZR, rn, o);
@@ -1196,11 +1199,13 @@
}
// Branching to ExternalLabels.
- void Branch(const ExternalLabel* label, Register pp) {
- LoadExternalLabel(TMP, label, kNotPatchable, pp);
+ void Branch(const ExternalLabel* label) {
+ LoadExternalLabel(TMP, label);
br(TMP);
}
+ void Branch(const StubEntry& stub_entry);
+
// Fixed length branch to label.
void BranchPatchable(const ExternalLabel* label) {
// TODO(zra): Use LoadExternalLabelFixed if possible.
@@ -1208,69 +1213,65 @@
br(TMP);
}
- void BranchLink(const ExternalLabel* label, Register pp) {
- LoadExternalLabel(TMP, label, kNotPatchable, pp);
+ void BranchPatchable(const StubEntry& stub_entry);
+
+ void BranchLink(const ExternalLabel* label) {
+ LoadExternalLabel(TMP, label);
blr(TMP);
}
+ void BranchLink(const StubEntry& stub_entry);
+
// BranchLinkPatchable must be a fixed-length sequence so we can patch it
// with the debugger.
void BranchLinkPatchable(const ExternalLabel* label) {
- LoadExternalLabelFixed(TMP, label, kPatchable, PP);
+ LoadExternalLabelFixed(TMP, label, kPatchable);
blr(TMP);
}
+ void BranchLinkPatchable(const StubEntry& stub_entry);
+
// Macros accepting a pp Register argument may attempt to load values from
// the object pool when possible. Unless you are sure that the untagged object
// pool pointer is in another register, or that it is not available at all,
// PP should be passed for pp.
- void AddImmediate(Register dest, Register rn, int64_t imm, Register pp);
- void AddImmediateSetFlags(
- Register dest, Register rn, int64_t imm, Register pp);
- void SubImmediateSetFlags(
- Register dest, Register rn, int64_t imm, Register pp);
- void AndImmediate(Register rd, Register rn, int64_t imm, Register pp);
- void OrImmediate(Register rd, Register rn, int64_t imm, Register pp);
- void XorImmediate(Register rd, Register rn, int64_t imm, Register pp);
- void TestImmediate(Register rn, int64_t imm, Register pp);
- void CompareImmediate(Register rn, int64_t imm, Register pp);
+ void AddImmediate(Register dest, Register rn, int64_t imm);
+ void AddImmediateSetFlags(Register dest, Register rn, int64_t imm);
+ void SubImmediateSetFlags(Register dest, Register rn, int64_t imm);
+ void AndImmediate(Register rd, Register rn, int64_t imm);
+ void OrImmediate(Register rd, Register rn, int64_t imm);
+ void XorImmediate(Register rd, Register rn, int64_t imm);
+ void TestImmediate(Register rn, int64_t imm);
+ void CompareImmediate(Register rn, int64_t imm);
void LoadFromOffset(Register dest, Register base, int32_t offset,
- Register pp, OperandSize sz = kDoubleWord);
+ OperandSize sz = kDoubleWord);
void LoadFieldFromOffset(Register dest, Register base, int32_t offset,
- Register pp, OperandSize sz = kDoubleWord) {
- LoadFromOffset(dest, base, offset - kHeapObjectTag, pp, sz);
+ OperandSize sz = kDoubleWord) {
+ LoadFromOffset(dest, base, offset - kHeapObjectTag, sz);
}
- void LoadDFromOffset(
- VRegister dest, Register base, int32_t offset, Register pp);
- void LoadDFieldFromOffset(
- VRegister dest, Register base, int32_t offset, Register pp) {
- LoadDFromOffset(dest, base, offset - kHeapObjectTag, pp);
+ void LoadDFromOffset(VRegister dest, Register base, int32_t offset);
+ void LoadDFieldFromOffset(VRegister dest, Register base, int32_t offset) {
+ LoadDFromOffset(dest, base, offset - kHeapObjectTag);
}
- void LoadQFromOffset(
- VRegister dest, Register base, int32_t offset, Register pp);
- void LoadQFieldFromOffset(
- VRegister dest, Register base, int32_t offset, Register pp) {
- LoadQFromOffset(dest, base, offset - kHeapObjectTag, pp);
+ void LoadQFromOffset(VRegister dest, Register base, int32_t offset);
+ void LoadQFieldFromOffset(VRegister dest, Register base, int32_t offset) {
+ LoadQFromOffset(dest, base, offset - kHeapObjectTag);
}
void StoreToOffset(Register src, Register base, int32_t offset,
- Register pp, OperandSize sz = kDoubleWord);
+ OperandSize sz = kDoubleWord);
void StoreFieldToOffset(Register src, Register base, int32_t offset,
- Register pp, OperandSize sz = kDoubleWord) {
- StoreToOffset(src, base, offset - kHeapObjectTag, pp, sz);
+ OperandSize sz = kDoubleWord) {
+ StoreToOffset(src, base, offset - kHeapObjectTag, sz);
}
- void StoreDToOffset(
- VRegister src, Register base, int32_t offset, Register pp);
- void StoreDFieldToOffset(
- VRegister src, Register base, int32_t offset, Register pp) {
- StoreDToOffset(src, base, offset - kHeapObjectTag, pp);
+ void StoreDToOffset(VRegister src, Register base, int32_t offset);
+ void StoreDFieldToOffset(VRegister src, Register base, int32_t offset) {
+ StoreDToOffset(src, base, offset - kHeapObjectTag);
}
- void StoreQToOffset(
- VRegister src, Register base, int32_t offset, Register pp);
- void StoreQFieldToOffset(
- VRegister src, Register base, int32_t offset, Register pp) {
- StoreQToOffset(src, base, offset - kHeapObjectTag, pp);
+ void StoreQToOffset(VRegister src, Register base, int32_t offset);
+ void StoreQFieldToOffset(VRegister src, Register base, int32_t offset) {
+ StoreQToOffset(src, base, offset - kHeapObjectTag);
}
// Storing into an object.
@@ -1281,62 +1282,59 @@
void StoreIntoObjectOffset(Register object,
int32_t offset,
Register value,
- Register pp,
bool can_value_be_smi = true);
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
Register value);
void StoreIntoObjectOffsetNoBarrier(Register object,
int32_t offset,
- Register value,
- Register pp);
+ Register value);
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
const Object& value);
void StoreIntoObjectOffsetNoBarrier(Register object,
int32_t offset,
- const Object& value,
- Register pp);
+ const Object& value);
// Object pool, loading from pool, etc.
- void LoadPoolPointer(Register pp);
+ void LoadPoolPointer(Register pp = PP);
- bool allow_constant_pool() const {
- return allow_constant_pool_;
+ bool constant_pool_allowed() const {
+ return constant_pool_allowed_;
}
- void set_allow_constant_pool(bool b) {
- allow_constant_pool_ = b;
+ void set_constant_pool_allowed(bool b) {
+ constant_pool_allowed_ = b;
}
- void LoadWordFromPoolOffset(Register dst, Register pp, uint32_t offset);
- void LoadWordFromPoolOffsetFixed(Register dst, Register pp, uint32_t offset);
+ void LoadWordFromPoolOffset(Register dst, uint32_t offset);
+ void LoadWordFromPoolOffsetFixed(Register dst, uint32_t offset);
intptr_t FindImmediate(int64_t imm);
bool CanLoadFromObjectPool(const Object& object) const;
- bool CanLoadImmediateFromPool(int64_t imm, Register pp);
- void LoadExternalLabel(Register dst, const ExternalLabel* label,
- Patchability patchable, Register pp);
+ void LoadExternalLabel(Register dst, const ExternalLabel* label);
void LoadExternalLabelFixed(Register dst,
const ExternalLabel* label,
- Patchability patchable,
- Register pp);
+ Patchability patchable);
+ void LoadFunctionFromCalleePool(Register dst,
+ const Function& function,
+ Register new_pp);
void LoadIsolate(Register dst);
- void LoadObject(Register dst, const Object& obj, Register pp);
- void LoadUniqueObject(Register dst, const Object& obj, Register pp);
- void LoadDecodableImmediate(Register reg, int64_t imm, Register pp);
+ void LoadObject(Register dst, const Object& obj);
+ void LoadUniqueObject(Register dst, const Object& obj);
+ void LoadDecodableImmediate(Register reg, int64_t imm);
void LoadImmediateFixed(Register reg, int64_t imm);
- void LoadImmediate(Register reg, int64_t imm, Register pp);
- void LoadDImmediate(VRegister reg, double immd, Register pp);
+ void LoadImmediate(Register reg, int64_t imm);
+ void LoadDImmediate(VRegister reg, double immd);
- void PushObject(const Object& object, Register pp) {
- LoadObject(TMP, object, pp);
+ void PushObject(const Object& object) {
+ LoadObject(TMP, object);
Push(TMP);
}
- void CompareObject(Register reg, const Object& object, Register pp);
+ void CompareObject(Register reg, const Object& object);
- void LoadClassId(Register result, Register object, Register pp);
- void LoadClassById(Register result, Register class_id, Register pp);
- void LoadClass(Register result, Register object, Register pp);
- void CompareClassId(Register object, intptr_t class_id, Register pp);
+ void LoadClassId(Register result, Register object);
+ void LoadClassById(Register result, Register class_id);
+ void LoadClass(Register result, Register object);
+ void CompareClassId(Register object, intptr_t class_id);
void LoadClassIdMayBeSmi(Register result, Register object);
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
@@ -1379,13 +1377,11 @@
void LeaveStubFrame();
void UpdateAllocationStats(intptr_t cid,
- Register pp,
Heap::Space space,
bool inline_isolate = true);
void UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
- Register pp,
Heap::Space space,
bool inline_isolate = true);
@@ -1393,8 +1389,8 @@
// which will allocate in the runtime where tracing occurs.
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Register pp,
- Label* trace);
+ Label* trace,
+ bool inline_isolate = true);
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
@@ -1403,8 +1399,7 @@
void TryAllocate(const Class& cls,
Label* failure,
Register instance_reg,
- Register temp_reg,
- Register pp);
+ Register temp_reg);
void TryAllocateArray(intptr_t cid,
intptr_t instance_size,
@@ -1452,12 +1447,9 @@
GrowableArray<CodeComment*> comments_;
- bool allow_constant_pool_;
+ bool constant_pool_allowed_;
- void LoadObjectHelper(Register dst,
- const Object& obj,
- Register pp,
- bool is_unique);
+ void LoadObjectHelper(Register dst, const Object& obj, bool is_unique);
void AddSubHelper(OperandSize os, bool set_flags, bool subtract,
Register rd, Register rn, Operand o) {
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index 28749b3..6fb9822 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -287,9 +287,9 @@
ASSEMBLER_TEST_GENERATE(AddCarryInOut, assembler) {
- __ LoadImmediate(R2, -1, kNoPP);
- __ LoadImmediate(R1, 1, kNoPP);
- __ LoadImmediate(R0, 0, kNoPP);
+ __ LoadImmediate(R2, -1);
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R0, 0);
__ adds(IP0, R2, Operand(R1)); // c_out = 1.
__ adcs(IP0, R2, R0); // c_in = 1, c_out = 1.
__ adc(R0, R0, R0); // c_in = 1.
@@ -304,8 +304,8 @@
ASSEMBLER_TEST_GENERATE(SubCarryInOut, assembler) {
- __ LoadImmediate(R1, 1, kNoPP);
- __ LoadImmediate(R0, 0, kNoPP);
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R0, 0);
__ subs(IP0, R0, Operand(R1)); // c_out = 1.
__ sbcs(IP0, R0, R0); // c_in = 1, c_out = 1.
__ sbc(R0, R0, R0); // c_in = 1.
@@ -320,10 +320,10 @@
ASSEMBLER_TEST_GENERATE(Overflow, assembler) {
- __ LoadImmediate(R0, 0, kNoPP);
- __ LoadImmediate(R1, 1, kNoPP);
- __ LoadImmediate(R2, 0xFFFFFFFFFFFFFFFF, kNoPP);
- __ LoadImmediate(R3, 0x7FFFFFFFFFFFFFFF, kNoPP);
+ __ LoadImmediate(R0, 0);
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R2, 0xFFFFFFFFFFFFFFFF);
+ __ LoadImmediate(R3, 0x7FFFFFFFFFFFFFFF);
__ adds(IP0, R2, Operand(R1)); // c_out = 1.
__ adcs(IP0, R3, R0); // c_in = 1, c_out = 1, v = 1.
__ csinc(R0, R0, R0, VS); // R0 = v ? R0 : R0 + 1.
@@ -338,9 +338,9 @@
ASSEMBLER_TEST_GENERATE(WordAddCarryInOut, assembler) {
- __ LoadImmediate(R2, -1, kNoPP);
- __ LoadImmediate(R1, 1, kNoPP);
- __ LoadImmediate(R0, 0, kNoPP);
+ __ LoadImmediate(R2, -1);
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R0, 0);
__ addsw(IP0, R2, Operand(R1)); // c_out = 1.
__ adcsw(IP0, R2, R0); // c_in = 1, c_out = 1.
__ adcw(R0, R0, R0); // c_in = 1.
@@ -355,8 +355,8 @@
ASSEMBLER_TEST_GENERATE(WordSubCarryInOut, assembler) {
- __ LoadImmediate(R1, 1, kNoPP);
- __ LoadImmediate(R0, 0, kNoPP);
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R0, 0);
__ subsw(IP0, R0, Operand(R1)); // c_out = 1.
__ sbcsw(IP0, R0, R0); // c_in = 1, c_out = 1.
__ sbcw(R0, R0, R0); // c_in = 1.
@@ -371,10 +371,10 @@
ASSEMBLER_TEST_GENERATE(WordOverflow, assembler) {
- __ LoadImmediate(R0, 0, kNoPP);
- __ LoadImmediate(R1, 1, kNoPP);
- __ LoadImmediate(R2, 0xFFFFFFFF, kNoPP);
- __ LoadImmediate(R3, 0x7FFFFFFF, kNoPP);
+ __ LoadImmediate(R0, 0);
+ __ LoadImmediate(R1, 1);
+ __ LoadImmediate(R2, 0xFFFFFFFF);
+ __ LoadImmediate(R3, 0x7FFFFFFF);
__ addsw(IP0, R2, Operand(R1)); // c_out = 1.
__ adcsw(IP0, R3, R0); // c_in = 1, c_out = 1, v = 1.
__ csinc(R0, R0, R0, VS); // R0 = v ? R0 : R0 + 1.
@@ -510,7 +510,7 @@
ASSEMBLER_TEST_GENERATE(LoadSigned32Bit, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadImmediate(R1, 0xffffffff, kNoPP);
+ __ LoadImmediate(R1, 0xffffffff);
__ str(R1, Address(SP, -4, Address::PreIndex, kWord), kWord);
__ ldr(R0, Address(SP), kWord);
__ ldr(R1, Address(SP, 4, Address::PostIndex, kWord), kWord);
@@ -527,8 +527,8 @@
ASSEMBLER_TEST_GENERATE(SimpleLoadStorePair, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadImmediate(R2, 43, kNoPP);
- __ LoadImmediate(R3, 42, kNoPP);
+ __ LoadImmediate(R2, 43);
+ __ LoadImmediate(R3, 42);
__ stp(R2, R3, Address(SP, -2*kWordSize, Address::PairPreIndex));
__ ldp(R0, R1, Address(SP, 2*kWordSize, Address::PairPostIndex));
__ sub(R0, R0, Operand(R1));
@@ -545,8 +545,8 @@
ASSEMBLER_TEST_GENERATE(LoadStorePairOffset, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadImmediate(R2, 43, kNoPP);
- __ LoadImmediate(R3, 42, kNoPP);
+ __ LoadImmediate(R2, 43);
+ __ LoadImmediate(R3, 42);
__ sub(SP, SP, Operand(4 * kWordSize));
__ stp(R2, R3, Address::Pair(SP, 2 * kWordSize));
__ ldp(R0, R1, Address::Pair(SP, 2 * kWordSize));
@@ -729,11 +729,11 @@
__ clz(R1, ZR);
__ cmp(R1, Operand(64));
__ b(&error, NE);
- __ LoadImmediate(R2, 42, kNoPP);
+ __ LoadImmediate(R2, 42);
__ clz(R2, R2);
__ cmp(R2, Operand(58));
__ b(&error, NE);
- __ LoadImmediate(R0, -1, kNoPP);
+ __ LoadImmediate(R0, -1);
__ clz(R1, R0);
__ cmp(R1, Operand(0));
__ b(&error, NE);
@@ -744,7 +744,7 @@
__ mov(R0, ZR);
__ ret();
__ Bind(&error);
- __ LoadImmediate(R0, 1, kNoPP);
+ __ LoadImmediate(R0, 1);
__ ret();
}
@@ -998,13 +998,13 @@
ASSEMBLER_TEST_GENERATE(FcmpEqBranch, assembler) {
Label l;
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, 234.0, kNoPP);
- __ LoadDImmediate(V2, 234.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, 234.0);
+ __ LoadDImmediate(V2, 234.0);
__ fcmpd(V1, V2);
__ b(&l, EQ);
- __ LoadDImmediate(V0, 0.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
__ Bind(&l);
__ ret();
}
@@ -1019,13 +1019,13 @@
ASSEMBLER_TEST_GENERATE(FcmpEqBranchNotTaken, assembler) {
Label l;
- __ LoadDImmediate(V0, 0.0, kNoPP);
- __ LoadDImmediate(V1, 233.0, kNoPP);
- __ LoadDImmediate(V2, 234.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
+ __ LoadDImmediate(V1, 233.0);
+ __ LoadDImmediate(V2, 234.0);
__ fcmpd(V1, V2);
__ b(&l, EQ);
- __ LoadDImmediate(V0, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
__ Bind(&l);
__ ret();
}
@@ -1040,13 +1040,13 @@
ASSEMBLER_TEST_GENERATE(FcmpLtBranch, assembler) {
Label l;
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, 233.0, kNoPP);
- __ LoadDImmediate(V2, 234.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, 233.0);
+ __ LoadDImmediate(V2, 234.0);
__ fcmpd(V1, V2);
__ b(&l, LT);
- __ LoadDImmediate(V0, 0.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
__ Bind(&l);
__ ret();
}
@@ -1061,13 +1061,13 @@
ASSEMBLER_TEST_GENERATE(FcmpLtBranchNotTaken, assembler) {
Label l;
- __ LoadDImmediate(V0, 0.0, kNoPP);
- __ LoadDImmediate(V1, 235.0, kNoPP);
- __ LoadDImmediate(V2, 234.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
+ __ LoadDImmediate(V1, 235.0);
+ __ LoadDImmediate(V2, 234.0);
__ fcmpd(V1, V2);
__ b(&l, LT);
- __ LoadDImmediate(V0, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
__ Bind(&l);
__ ret();
}
@@ -1082,15 +1082,15 @@
ASSEMBLER_TEST_GENERATE(FcmpzGtBranch, assembler) {
Label l;
- __ LoadDImmediate(V0, 235.0, kNoPP);
- __ LoadDImmediate(V1, 233.0, kNoPP);
+ __ LoadDImmediate(V0, 235.0);
+ __ LoadDImmediate(V1, 233.0);
__ fcmpdz(V1);
__ b(&l, GT);
- __ LoadDImmediate(V0, 0.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
__ ret();
__ Bind(&l);
- __ LoadDImmediate(V0, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
__ ret();
}
@@ -1513,7 +1513,7 @@
// Loading immediate values without the object pool.
ASSEMBLER_TEST_GENERATE(LoadImmediateSmall, assembler) {
- __ LoadImmediate(R0, 42, kNoRegister);
+ __ LoadImmediate(R0, 42);
__ ret();
}
@@ -1525,7 +1525,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateMed, assembler) {
- __ LoadImmediate(R0, 0xf1234123, kNoRegister);
+ __ LoadImmediate(R0, 0xf1234123);
__ ret();
}
@@ -1537,7 +1537,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateMed2, assembler) {
- __ LoadImmediate(R0, 0x4321f1234123, kNoRegister);
+ __ LoadImmediate(R0, 0x4321f1234123);
__ ret();
}
@@ -1550,7 +1550,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateLarge, assembler) {
- __ LoadImmediate(R0, 0x9287436598237465, kNoRegister);
+ __ LoadImmediate(R0, 0x9287436598237465);
__ ret();
}
@@ -1563,7 +1563,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateSmallNeg, assembler) {
- __ LoadImmediate(R0, -42, kNoRegister);
+ __ LoadImmediate(R0, -42);
__ ret();
}
@@ -1575,7 +1575,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateMedNeg, assembler) {
- __ LoadImmediate(R0, -0x1212341234, kNoRegister);
+ __ LoadImmediate(R0, -0x1212341234);
__ ret();
}
@@ -1587,7 +1587,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateMedNeg2, assembler) {
- __ LoadImmediate(R0, -0x1212340000, kNoRegister);
+ __ LoadImmediate(R0, -0x1212340000);
__ ret();
}
@@ -1599,7 +1599,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateMedNeg3, assembler) {
- __ LoadImmediate(R0, -0x1200001234, kNoRegister);
+ __ LoadImmediate(R0, -0x1200001234);
__ ret();
}
@@ -1611,7 +1611,7 @@
ASSEMBLER_TEST_GENERATE(LoadImmediateMedNeg4, assembler) {
- __ LoadImmediate(R0, -0x12341234, kNoRegister);
+ __ LoadImmediate(R0, -0x12341234);
__ ret();
}
@@ -1626,8 +1626,8 @@
ASSEMBLER_TEST_GENERATE(LoadImmediatePPSmall, assembler) {
__ SetupDartSP(kTestStackSpace);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadImmediate(R0, 42, PP);
+ __ LoadPoolPointer();
+ __ LoadImmediate(R0, 42);
__ PopAndUntagPP();
__ mov(CSP, SP);
__ ret();
@@ -1643,8 +1643,8 @@
ASSEMBLER_TEST_GENERATE(LoadImmediatePPMed, assembler) {
__ SetupDartSP(kTestStackSpace);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadImmediate(R0, 0xf1234123, PP);
+ __ LoadPoolPointer();
+ __ LoadImmediate(R0, 0xf1234123);
__ PopAndUntagPP();
__ mov(CSP, SP);
__ ret();
@@ -1660,8 +1660,8 @@
ASSEMBLER_TEST_GENERATE(LoadImmediatePPMed2, assembler) {
__ SetupDartSP(kTestStackSpace);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadImmediate(R0, 0x4321f1234124, PP);
+ __ LoadPoolPointer();
+ __ LoadImmediate(R0, 0x4321f1234124);
__ PopAndUntagPP();
__ mov(CSP, SP);
__ ret();
@@ -1678,8 +1678,8 @@
ASSEMBLER_TEST_GENERATE(LoadImmediatePPLarge, assembler) {
__ SetupDartSP(kTestStackSpace);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadImmediate(R0, 0x9287436598237465, PP);
+ __ LoadPoolPointer();
+ __ LoadImmediate(R0, 0x9287436598237465);
__ PopAndUntagPP();
__ mov(CSP, SP);
__ ret();
@@ -1713,8 +1713,8 @@
__ Push(THR);
__ mov(THR, R0);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadObject(R0, Object::null_object(), PP);
+ __ LoadPoolPointer();
+ __ LoadObject(R0, Object::null_object());
__ PopAndUntagPP();
__ Pop(THR);
__ mov(CSP, SP);
@@ -1733,8 +1733,8 @@
__ Push(THR);
__ mov(THR, R0);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadObject(R0, Bool::True(), PP);
+ __ LoadPoolPointer();
+ __ LoadObject(R0, Bool::True());
__ PopAndUntagPP();
__ Pop(THR);
__ mov(CSP, SP);
@@ -1753,8 +1753,8 @@
__ Push(THR);
__ mov(THR, R0);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadObject(R0, Bool::False(), PP);
+ __ LoadPoolPointer();
+ __ LoadObject(R0, Bool::False());
__ PopAndUntagPP();
__ Pop(THR);
__ mov(CSP, SP);
@@ -1769,8 +1769,8 @@
ASSEMBLER_TEST_GENERATE(CSelTrue, assembler) {
- __ LoadImmediate(R1, 42, kNoRegister);
- __ LoadImmediate(R2, 1234, kNoRegister);
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 1234);
__ CompareRegisters(R1, R2);
__ csel(R0, R1, R2, LT);
__ ret();
@@ -1784,8 +1784,8 @@
ASSEMBLER_TEST_GENERATE(CSelFalse, assembler) {
- __ LoadImmediate(R1, 42, kNoRegister);
- __ LoadImmediate(R2, 1234, kNoRegister);
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 1234);
__ CompareRegisters(R1, R2);
__ csel(R0, R1, R2, GE);
__ ret();
@@ -1799,8 +1799,8 @@
ASSEMBLER_TEST_GENERATE(CsincFalse, assembler) {
- __ LoadImmediate(R1, 42, kNoRegister);
- __ LoadImmediate(R2, 1234, kNoRegister);
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 1234);
__ CompareRegisters(R1, R2);
__ csinc(R0, R2, R1, GE);
__ ret();
@@ -1814,8 +1814,8 @@
ASSEMBLER_TEST_GENERATE(CsincTrue, assembler) {
- __ LoadImmediate(R1, 42, kNoRegister);
- __ LoadImmediate(R2, 1234, kNoRegister);
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 1234);
__ CompareRegisters(R1, R2);
__ csinc(R0, R2, R1, LT);
__ ret();
@@ -1829,8 +1829,8 @@
ASSEMBLER_TEST_GENERATE(CsinvFalse, assembler) {
- __ LoadImmediate(R1, 42, kNoRegister);
- __ LoadImmediate(R2, 1234, kNoRegister);
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 1234);
__ CompareRegisters(R1, R2);
__ csinv(R0, R2, R1, GE);
__ ret();
@@ -1844,8 +1844,8 @@
ASSEMBLER_TEST_GENERATE(CsinvTrue, assembler) {
- __ LoadImmediate(R1, 42, kNoRegister);
- __ LoadImmediate(R2, 1234, kNoRegister);
+ __ LoadImmediate(R1, 42);
+ __ LoadImmediate(R2, 1234);
__ CompareRegisters(R1, R2);
__ csinv(R0, R2, R1, LT);
__ ret();
@@ -1860,7 +1860,7 @@
// Floating point move immediate, to/from integer register.
ASSEMBLER_TEST_GENERATE(Fmovdi, assembler) {
- __ LoadDImmediate(V0, 1.0, kNoPP);
+ __ LoadDImmediate(V0, 1.0);
__ ret();
}
@@ -1872,7 +1872,7 @@
ASSEMBLER_TEST_GENERATE(Fmovdi2, assembler) {
- __ LoadDImmediate(V0, 123412983.1324524315, kNoPP);
+ __ LoadDImmediate(V0, 123412983.1324524315);
__ ret();
}
@@ -1885,7 +1885,7 @@
ASSEMBLER_TEST_GENERATE(Fmovrd, assembler) {
- __ LoadDImmediate(V1, 1.0, kNoPP);
+ __ LoadDImmediate(V1, 1.0);
__ fmovrd(R0, V1);
__ ret();
}
@@ -1899,7 +1899,7 @@
ASSEMBLER_TEST_GENERATE(Fmovdr, assembler) {
- __ LoadDImmediate(V1, 1.0, kNoPP);
+ __ LoadDImmediate(V1, 1.0);
__ fmovrd(R1, V1);
__ fmovdr(V0, R1);
__ ret();
@@ -1914,7 +1914,7 @@
ASSEMBLER_TEST_GENERATE(FldrdFstrdPrePostIndex, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V1, 42.0);
__ fstrd(V1, Address(SP, -1*kWordSize, Address::PreIndex));
__ fldrd(V0, Address(SP, 1*kWordSize, Address::PostIndex));
__ mov(CSP, SP);
@@ -1930,7 +1930,7 @@
ASSEMBLER_TEST_GENERATE(FldrsFstrsPrePostIndex, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V1, 42.0);
__ fcvtsd(V2, V1);
__ fstrs(V2, Address(SP, -1*kWordSize, Address::PreIndex));
__ fldrs(V3, Address(SP, 1*kWordSize, Address::PostIndex));
@@ -1948,9 +1948,9 @@
ASSEMBLER_TEST_GENERATE(FldrqFstrqPrePostIndex, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V1, 21.0, kNoPP);
- __ LoadDImmediate(V2, 21.0, kNoPP);
- __ LoadImmediate(R1, 42, kNoPP);
+ __ LoadDImmediate(V1, 21.0);
+ __ LoadDImmediate(V2, 21.0);
+ __ LoadImmediate(R1, 42);
__ Push(R1);
__ PushDouble(V1);
__ PushDouble(V2);
@@ -1972,7 +1972,7 @@
ASSEMBLER_TEST_GENERATE(Fcvtzds, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
__ fcvtzds(R0, V0);
__ ret();
}
@@ -1985,7 +1985,7 @@
ASSEMBLER_TEST_GENERATE(Scvtfdx, assembler) {
- __ LoadImmediate(R0, 42, kNoPP);
+ __ LoadImmediate(R0, 42);
__ scvtfdx(V0, R0);
__ ret();
}
@@ -1999,7 +1999,7 @@
ASSEMBLER_TEST_GENERATE(Scvtfdw, assembler) {
// Fill upper 32-bits with garbage.
- __ LoadImmediate(R0, 0x111111110000002A, kNoPP);
+ __ LoadImmediate(R0, 0x111111110000002A);
__ scvtfdw(V0, R0);
__ ret();
}
@@ -2012,7 +2012,7 @@
ASSEMBLER_TEST_GENERATE(FabsdPos, assembler) {
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V1, 42.0);
__ fabsd(V0, V1);
__ ret();
}
@@ -2025,7 +2025,7 @@
ASSEMBLER_TEST_GENERATE(FabsdNeg, assembler) {
- __ LoadDImmediate(V1, -42.0, kNoPP);
+ __ LoadDImmediate(V1, -42.0);
__ fabsd(V0, V1);
__ ret();
}
@@ -2038,7 +2038,7 @@
ASSEMBLER_TEST_GENERATE(FnegdPos, assembler) {
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V1, 42.0);
__ fnegd(V0, V1);
__ ret();
}
@@ -2051,7 +2051,7 @@
ASSEMBLER_TEST_GENERATE(FnegdNeg, assembler) {
- __ LoadDImmediate(V1, -42.0, kNoPP);
+ __ LoadDImmediate(V1, -42.0);
__ fnegd(V0, V1);
__ ret();
}
@@ -2064,7 +2064,7 @@
ASSEMBLER_TEST_GENERATE(Fsqrtd, assembler) {
- __ LoadDImmediate(V1, 64.0, kNoPP);
+ __ LoadDImmediate(V1, 64.0);
__ fsqrtd(V0, V1);
__ ret();
}
@@ -2077,8 +2077,8 @@
ASSEMBLER_TEST_GENERATE(Fmuld, assembler) {
- __ LoadDImmediate(V1, 84.0, kNoPP);
- __ LoadDImmediate(V2, 0.5, kNoPP);
+ __ LoadDImmediate(V1, 84.0);
+ __ LoadDImmediate(V2, 0.5);
__ fmuld(V0, V1, V2);
__ ret();
}
@@ -2091,8 +2091,8 @@
ASSEMBLER_TEST_GENERATE(Fdivd, assembler) {
- __ LoadDImmediate(V1, 84.0, kNoPP);
- __ LoadDImmediate(V2, 2.0, kNoPP);
+ __ LoadDImmediate(V1, 84.0);
+ __ LoadDImmediate(V2, 2.0);
__ fdivd(V0, V1, V2);
__ ret();
}
@@ -2105,8 +2105,8 @@
ASSEMBLER_TEST_GENERATE(Faddd, assembler) {
- __ LoadDImmediate(V1, 41.5, kNoPP);
- __ LoadDImmediate(V2, 0.5, kNoPP);
+ __ LoadDImmediate(V1, 41.5);
+ __ LoadDImmediate(V2, 0.5);
__ faddd(V0, V1, V2);
__ ret();
}
@@ -2119,8 +2119,8 @@
ASSEMBLER_TEST_GENERATE(Fsubd, assembler) {
- __ LoadDImmediate(V1, 42.5, kNoPP);
- __ LoadDImmediate(V2, 0.5, kNoPP);
+ __ LoadDImmediate(V1, 42.5);
+ __ LoadDImmediate(V2, 0.5);
__ fsubd(V0, V1, V2);
__ ret();
}
@@ -2134,13 +2134,13 @@
ASSEMBLER_TEST_GENERATE(FldrdFstrdHeapTag, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 43.0, kNoPP);
- __ LoadDImmediate(V1, 42.0, kNoPP);
- __ AddImmediate(SP, SP, -1 * kWordSize, kNoPP);
+ __ LoadDImmediate(V0, 43.0);
+ __ LoadDImmediate(V1, 42.0);
+ __ AddImmediate(SP, SP, -1 * kWordSize);
__ add(R2, SP, Operand(1));
__ fstrd(V1, Address(R2, -1));
__ fldrd(V0, Address(R2, -1));
- __ AddImmediate(SP, SP, 1 * kWordSize, kNoPP);
+ __ AddImmediate(SP, SP, 1 * kWordSize);
__ mov(CSP, SP);
__ ret();
}
@@ -2154,8 +2154,8 @@
ASSEMBLER_TEST_GENERATE(FldrdFstrdLargeIndex, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 43.0, kNoPP);
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 43.0);
+ __ LoadDImmediate(V1, 42.0);
// Largest negative offset that can fit in the signed 9-bit immediate field.
__ fstrd(V1, Address(SP, -32*kWordSize, Address::PreIndex));
// Largest positive kWordSize aligned offset that we can fit.
@@ -2175,8 +2175,8 @@
ASSEMBLER_TEST_GENERATE(FldrdFstrdLargeOffset, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 43.0, kNoPP);
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 43.0);
+ __ LoadDImmediate(V1, 42.0);
__ sub(SP, SP, Operand(512*kWordSize));
__ fstrd(V1, Address(SP, 512*kWordSize, Address::Offset));
__ add(SP, SP, Operand(512*kWordSize));
@@ -2194,8 +2194,8 @@
ASSEMBLER_TEST_GENERATE(FldrdFstrdExtReg, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 43.0, kNoPP);
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 43.0);
+ __ LoadDImmediate(V1, 42.0);
__ movz(R2, Immediate(0xfff8), 0);
__ movk(R2, Immediate(0xffff), 1); // R2 <- -8 (int32_t).
// This should sign extend R2, and add to SP to get address,
@@ -2217,8 +2217,8 @@
ASSEMBLER_TEST_GENERATE(FldrdFstrdScaledReg, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 43.0, kNoPP);
- __ LoadDImmediate(V1, 42.0, kNoPP);
+ __ LoadDImmediate(V0, 43.0);
+ __ LoadDImmediate(V1, 42.0);
__ movz(R2, Immediate(10), 0);
__ sub(SP, SP, Operand(10*kWordSize));
// Store V1 into SP + R2 * kWordSize.
@@ -2237,10 +2237,10 @@
ASSEMBLER_TEST_GENERATE(VinswVmovrs, assembler) {
- __ LoadImmediate(R0, 42, kNoPP);
- __ LoadImmediate(R1, 43, kNoPP);
- __ LoadImmediate(R2, 44, kNoPP);
- __ LoadImmediate(R3, 45, kNoPP);
+ __ LoadImmediate(R0, 42);
+ __ LoadImmediate(R1, 43);
+ __ LoadImmediate(R2, 44);
+ __ LoadImmediate(R3, 45);
__ vinsw(V0, 0, R0);
__ vinsw(V0, 1, R1);
@@ -2267,8 +2267,8 @@
ASSEMBLER_TEST_GENERATE(VinsxVmovrd, assembler) {
- __ LoadImmediate(R0, 42, kNoPP);
- __ LoadImmediate(R1, 43, kNoPP);
+ __ LoadImmediate(R0, 42);
+ __ LoadImmediate(R1, 43);
__ vinsx(V0, 0, R0);
__ vinsx(V0, 1, R1);
@@ -2289,8 +2289,8 @@
ASSEMBLER_TEST_GENERATE(Vnot, assembler) {
- __ LoadImmediate(R0, 0xfffffffe, kNoPP);
- __ LoadImmediate(R1, 0xffffffff, kNoPP);
+ __ LoadImmediate(R0, 0xfffffffe);
+ __ LoadImmediate(R1, 0xffffffff);
__ vinsw(V1, 0, R1);
__ vinsw(V1, 1, R0);
__ vinsw(V1, 2, R1);
@@ -2317,8 +2317,8 @@
ASSEMBLER_TEST_GENERATE(Vabss, assembler) {
- __ LoadDImmediate(V1, 21.0, kNoPP);
- __ LoadDImmediate(V2, -21.0, kNoPP);
+ __ LoadDImmediate(V1, 21.0);
+ __ LoadDImmediate(V2, -21.0);
__ fcvtsd(V1, V1);
__ fcvtsd(V2, V2);
@@ -2347,8 +2347,8 @@
ASSEMBLER_TEST_GENERATE(Vabsd, assembler) {
- __ LoadDImmediate(V1, 21.0, kNoPP);
- __ LoadDImmediate(V2, -21.0, kNoPP);
+ __ LoadDImmediate(V1, 21.0);
+ __ LoadDImmediate(V2, -21.0);
__ vinsd(V3, 0, V1, 0);
__ vinsd(V3, 1, V2, 0);
@@ -2370,8 +2370,8 @@
ASSEMBLER_TEST_GENERATE(Vnegs, assembler) {
- __ LoadDImmediate(V1, 42.0, kNoPP);
- __ LoadDImmediate(V2, -84.0, kNoPP);
+ __ LoadDImmediate(V1, 42.0);
+ __ LoadDImmediate(V2, -84.0);
__ fcvtsd(V1, V1);
__ fcvtsd(V2, V2);
@@ -2399,8 +2399,8 @@
ASSEMBLER_TEST_GENERATE(Vnegd, assembler) {
- __ LoadDImmediate(V1, 42.0, kNoPP);
- __ LoadDImmediate(V2, -84.0, kNoPP);
+ __ LoadDImmediate(V1, 42.0);
+ __ LoadDImmediate(V2, -84.0);
__ vinsd(V3, 0, V1, 0);
__ vinsd(V3, 1, V2, 0);
@@ -2422,10 +2422,10 @@
ASSEMBLER_TEST_GENERATE(Vadds, assembler) {
- __ LoadDImmediate(V0, 0.0, kNoPP);
- __ LoadDImmediate(V1, 1.0, kNoPP);
- __ LoadDImmediate(V2, 2.0, kNoPP);
- __ LoadDImmediate(V3, 3.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
+ __ LoadDImmediate(V1, 1.0);
+ __ LoadDImmediate(V2, 2.0);
+ __ LoadDImmediate(V3, 3.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -2463,11 +2463,11 @@
ASSEMBLER_TEST_GENERATE(Vsubs, assembler) {
- __ LoadDImmediate(V0, 0.0, kNoPP);
- __ LoadDImmediate(V1, 1.0, kNoPP);
- __ LoadDImmediate(V2, 2.0, kNoPP);
- __ LoadDImmediate(V3, 3.0, kNoPP);
- __ LoadDImmediate(V5, 0.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
+ __ LoadDImmediate(V1, 1.0);
+ __ LoadDImmediate(V2, 2.0);
+ __ LoadDImmediate(V3, 3.0);
+ __ LoadDImmediate(V5, 0.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -2505,10 +2505,10 @@
ASSEMBLER_TEST_GENERATE(Vmuls, assembler) {
- __ LoadDImmediate(V0, 0.0, kNoPP);
- __ LoadDImmediate(V1, 1.0, kNoPP);
- __ LoadDImmediate(V2, 2.0, kNoPP);
- __ LoadDImmediate(V3, 3.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
+ __ LoadDImmediate(V1, 1.0);
+ __ LoadDImmediate(V2, 2.0);
+ __ LoadDImmediate(V3, 3.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -2546,10 +2546,10 @@
ASSEMBLER_TEST_GENERATE(Vdivs, assembler) {
- __ LoadDImmediate(V0, 0.0, kNoPP);
- __ LoadDImmediate(V1, 1.0, kNoPP);
- __ LoadDImmediate(V2, 2.0, kNoPP);
- __ LoadDImmediate(V3, 3.0, kNoPP);
+ __ LoadDImmediate(V0, 0.0);
+ __ LoadDImmediate(V1, 1.0);
+ __ LoadDImmediate(V2, 2.0);
+ __ LoadDImmediate(V3, 3.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -2587,8 +2587,8 @@
ASSEMBLER_TEST_GENERATE(Vaddd, assembler) {
- __ LoadDImmediate(V0, 2.0, kNoPP);
- __ LoadDImmediate(V1, 3.0, kNoPP);
+ __ LoadDImmediate(V0, 2.0);
+ __ LoadDImmediate(V1, 3.0);
__ vinsd(V4, 0, V0, 0);
__ vinsd(V4, 1, V1, 0);
@@ -2610,9 +2610,9 @@
ASSEMBLER_TEST_GENERATE(Vsubd, assembler) {
- __ LoadDImmediate(V0, 2.0, kNoPP);
- __ LoadDImmediate(V1, 3.0, kNoPP);
- __ LoadDImmediate(V5, 0.0, kNoPP);
+ __ LoadDImmediate(V0, 2.0);
+ __ LoadDImmediate(V1, 3.0);
+ __ LoadDImmediate(V5, 0.0);
__ vinsd(V4, 0, V0, 0);
__ vinsd(V4, 1, V1, 0);
@@ -2634,8 +2634,8 @@
ASSEMBLER_TEST_GENERATE(Vmuld, assembler) {
- __ LoadDImmediate(V0, 2.0, kNoPP);
- __ LoadDImmediate(V1, 3.0, kNoPP);
+ __ LoadDImmediate(V0, 2.0);
+ __ LoadDImmediate(V1, 3.0);
__ vinsd(V4, 0, V0, 0);
__ vinsd(V4, 1, V1, 0);
@@ -2657,8 +2657,8 @@
ASSEMBLER_TEST_GENERATE(Vdivd, assembler) {
- __ LoadDImmediate(V0, 2.0, kNoPP);
- __ LoadDImmediate(V1, 3.0, kNoPP);
+ __ LoadDImmediate(V0, 2.0);
+ __ LoadDImmediate(V1, 3.0);
__ vinsd(V4, 0, V0, 0);
__ vinsd(V4, 1, V1, 0);
@@ -2681,7 +2681,7 @@
ASSEMBLER_TEST_GENERATE(Vdupd, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 21.0, kNoPP);
+ __ LoadDImmediate(V0, 21.0);
__ vdupd(V1, V0, 0);
const int dword_bytes = 1 << Log2OperandSizeBytes(kDWord);
@@ -2705,7 +2705,7 @@
ASSEMBLER_TEST_GENERATE(Vdups, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 21.0, kNoPP);
+ __ LoadDImmediate(V0, 21.0);
__ fcvtsd(V0, V0);
__ vdups(V1, V0, 0);
@@ -2739,7 +2739,7 @@
ASSEMBLER_TEST_GENERATE(Vinsd, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V5, 42.0, kNoPP);
+ __ LoadDImmediate(V5, 42.0);
__ vinsd(V1, 1, V5, 0); // V1[1] <- V0[0].
const int dword_bytes = 1 << Log2OperandSizeBytes(kDWord);
@@ -2763,7 +2763,7 @@
ASSEMBLER_TEST_GENERATE(Vinss, assembler) {
__ SetupDartSP(kTestStackSpace);
- __ LoadDImmediate(V0, 21.0, kNoPP);
+ __ LoadDImmediate(V0, 21.0);
__ fcvtsd(V0, V0);
__ vinss(V1, 3, V0, 0);
__ vinss(V1, 1, V0, 0);
@@ -2797,8 +2797,8 @@
ASSEMBLER_TEST_GENERATE(Vand, assembler) {
- __ LoadDImmediate(V1, 21.0, kNoPP);
- __ LoadImmediate(R0, 0xffffffff, kNoPP);
+ __ LoadDImmediate(V1, 21.0);
+ __ LoadImmediate(R0, 0xffffffff);
// V0 <- (0, 0xffffffff, 0, 0xffffffff)
__ fmovdr(V0, R0);
@@ -2834,7 +2834,7 @@
ASSEMBLER_TEST_GENERATE(Vorr, assembler) {
- __ LoadDImmediate(V1, 10.5, kNoPP);
+ __ LoadDImmediate(V1, 10.5);
__ fcvtsd(V1, V1);
// V0 <- (0, 10.5, 0, 10.5)
@@ -2872,8 +2872,8 @@
ASSEMBLER_TEST_GENERATE(Veor, assembler) {
- __ LoadImmediate(R1, 0xffffffff, kNoPP);
- __ LoadImmediate(R2, ~21, kNoPP);
+ __ LoadImmediate(R1, 0xffffffff);
+ __ LoadImmediate(R2, ~21);
__ vinsw(V1, 0, R1);
__ vinsw(V1, 1, R2);
@@ -2906,7 +2906,7 @@
ASSEMBLER_TEST_GENERATE(Vaddw, assembler) {
- __ LoadImmediate(R4, 21, kNoPP);
+ __ LoadImmediate(R4, 21);
__ vdupw(V1, R4);
__ vdupw(V2, R4);
@@ -2931,8 +2931,8 @@
ASSEMBLER_TEST_GENERATE(Vsubw, assembler) {
- __ LoadImmediate(R4, 31, kNoPP);
- __ LoadImmediate(R5, 10, kNoPP);
+ __ LoadImmediate(R4, 31);
+ __ LoadImmediate(R5, 10);
__ vdupw(V1, R4);
__ vdupw(V2, R5);
@@ -2957,7 +2957,7 @@
ASSEMBLER_TEST_GENERATE(Vaddx, assembler) {
- __ LoadImmediate(R4, 21, kNoPP);
+ __ LoadImmediate(R4, 21);
__ vdupx(V1, R4);
__ vdupx(V2, R4);
@@ -2978,8 +2978,8 @@
ASSEMBLER_TEST_GENERATE(Vsubx, assembler) {
- __ LoadImmediate(R4, 31, kNoPP);
- __ LoadImmediate(R5, 10, kNoPP);
+ __ LoadImmediate(R4, 31);
+ __ LoadImmediate(R5, 10);
__ vdupx(V1, R4);
__ vdupx(V2, R5);
@@ -3000,8 +3000,8 @@
ASSEMBLER_TEST_GENERATE(Vceqs, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, -42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, -42.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -3033,8 +3033,8 @@
ASSEMBLER_TEST_GENERATE(Vceqd, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, -42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, -42.0);
__ vdupd(V2, V0, 0);
__ vinsd(V3, 0, V0, 0);
@@ -3057,8 +3057,8 @@
ASSEMBLER_TEST_GENERATE(Vcgts, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, -42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, -42.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -3090,8 +3090,8 @@
ASSEMBLER_TEST_GENERATE(Vcgtd, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, -42.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, -42.0);
__ vdupd(V2, V0, 0);
__ vinsd(V3, 0, V0, 0);
@@ -3114,8 +3114,8 @@
ASSEMBLER_TEST_GENERATE(Vcges, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, 43.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, 43.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -3147,8 +3147,8 @@
ASSEMBLER_TEST_GENERATE(Vcged, assembler) {
- __ LoadDImmediate(V0, 42.0, kNoPP);
- __ LoadDImmediate(V1, 43.0, kNoPP);
+ __ LoadDImmediate(V0, 42.0);
+ __ LoadDImmediate(V1, 43.0);
__ vdupd(V2, V0, 0);
__ vinsd(V3, 0, V0, 0);
@@ -3171,8 +3171,8 @@
ASSEMBLER_TEST_GENERATE(Vmaxs, assembler) {
- __ LoadDImmediate(V0, 10.5, kNoPP);
- __ LoadDImmediate(V1, 10.0, kNoPP);
+ __ LoadDImmediate(V0, 10.5);
+ __ LoadDImmediate(V1, 10.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -3209,8 +3209,8 @@
ASSEMBLER_TEST_GENERATE(Vmaxd, assembler) {
- __ LoadDImmediate(V0, 21.0, kNoPP);
- __ LoadDImmediate(V1, 20.5, kNoPP);
+ __ LoadDImmediate(V0, 21.0);
+ __ LoadDImmediate(V1, 20.5);
__ vdupd(V2, V0, 0);
__ vinsd(V3, 0, V0, 0);
@@ -3233,8 +3233,8 @@
ASSEMBLER_TEST_GENERATE(Vmins, assembler) {
- __ LoadDImmediate(V0, 10.5, kNoPP);
- __ LoadDImmediate(V1, 11.0, kNoPP);
+ __ LoadDImmediate(V0, 10.5);
+ __ LoadDImmediate(V1, 11.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -3271,8 +3271,8 @@
ASSEMBLER_TEST_GENERATE(Vmind, assembler) {
- __ LoadDImmediate(V0, 21.0, kNoPP);
- __ LoadDImmediate(V1, 21.5, kNoPP);
+ __ LoadDImmediate(V0, 21.0);
+ __ LoadDImmediate(V1, 21.5);
__ vdupd(V2, V0, 0);
__ vinsd(V3, 0, V0, 0);
@@ -3295,8 +3295,8 @@
ASSEMBLER_TEST_GENERATE(Vsqrts, assembler) {
- __ LoadDImmediate(V0, 64.0, kNoPP);
- __ LoadDImmediate(V1, 49.0, kNoPP);
+ __ LoadDImmediate(V0, 64.0);
+ __ LoadDImmediate(V1, 49.0);
__ fcvtsd(V0, V0);
__ fcvtsd(V1, V1);
@@ -3325,8 +3325,8 @@
ASSEMBLER_TEST_GENERATE(Vsqrtd, assembler) {
- __ LoadDImmediate(V0, 64.0, kNoPP);
- __ LoadDImmediate(V1, 49.0, kNoPP);
+ __ LoadDImmediate(V0, 64.0);
+ __ LoadDImmediate(V1, 49.0);
__ vinsd(V3, 0, V0, 0);
__ vinsd(V3, 1, V1, 0);
@@ -3383,7 +3383,7 @@
ASSEMBLER_TEST_GENERATE(Vrecpes, assembler) {
- __ LoadDImmediate(V1, 147.0, kNoPP);
+ __ LoadDImmediate(V1, 147.0);
__ fcvtsd(V1, V1);
__ vinss(V2, 0, V1, 0);
__ vinss(V2, 1, V1, 0);
@@ -3404,8 +3404,8 @@
ASSEMBLER_TEST_GENERATE(Vrecpss, assembler) {
- __ LoadDImmediate(V1, 5.0, kNoPP);
- __ LoadDImmediate(V2, 10.0, kNoPP);
+ __ LoadDImmediate(V1, 5.0);
+ __ LoadDImmediate(V2, 10.0);
__ fcvtsd(V1, V1);
__ fcvtsd(V2, V2);
@@ -3426,7 +3426,7 @@
ASSEMBLER_TEST_GENERATE(VRecps, assembler) {
- __ LoadDImmediate(V0, 1.0 / 10.5, kNoPP);
+ __ LoadDImmediate(V0, 1.0 / 10.5);
__ fcvtsd(V0, V0);
__ vdups(V1, V0, 0);
@@ -3509,7 +3509,7 @@
ASSEMBLER_TEST_GENERATE(Vrsqrtes, assembler) {
- __ LoadDImmediate(V1, 147.0, kNoPP);
+ __ LoadDImmediate(V1, 147.0);
__ fcvtsd(V1, V1);
__ vrsqrtes(V0, V1);
@@ -3528,8 +3528,8 @@
ASSEMBLER_TEST_GENERATE(Vrsqrtss, assembler) {
- __ LoadDImmediate(V1, 5.0, kNoPP);
- __ LoadDImmediate(V2, 10.0, kNoPP);
+ __ LoadDImmediate(V1, 5.0);
+ __ LoadDImmediate(V2, 10.0);
__ fcvtsd(V1, V1);
__ fcvtsd(V2, V2);
@@ -3550,7 +3550,7 @@
ASSEMBLER_TEST_GENERATE(ReciprocalSqrt, assembler) {
- __ LoadDImmediate(V1, 147000.0, kNoPP);
+ __ LoadDImmediate(V1, 147000.0);
__ fcvtsd(V1, V1);
__ VRSqrts(V0, V1);
@@ -3577,7 +3577,7 @@
ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
__ SetupDartSP(kTestStackSpace);
__ TagAndPushPP();
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ Push(THR);
__ Push(CTX);
__ Push(LR);
@@ -3598,14 +3598,14 @@
ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
__ SetupDartSP(kTestStackSpace);
__ TagAndPushPP();
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
Label miss, done;
__ mov(R1, R0);
__ ComputeRange(R0, R1, R2, &miss);
__ b(&done);
__ Bind(&miss);
- __ LoadImmediate(R0, -1, kNoPP);
+ __ LoadImmediate(R0, -1);
__ Bind(&done);
__ PopAndUntagPP();
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 8de5223..c6c8da8 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2366,8 +2366,7 @@
if (object != EDX) {
movl(EDX, object);
}
- StubCode* stub_code = Isolate::Current()->stub_code();
- call(&stub_code->UpdateStoreBufferLabel());
+ Call(*StubCode::UpdateStoreBuffer_entry());
if (value != EDX) {
popl(EDX); // Restore EDX.
}
@@ -2622,6 +2621,24 @@
}
+void Assembler::Call(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ call(&label);
+}
+
+
+void Assembler::Jmp(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ jmp(&label);
+}
+
+
+void Assembler::J(Condition condition, const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ j(condition, &label);
+}
+
+
void Assembler::Align(intptr_t alignment, intptr_t offset) {
ASSERT(Utils::IsPowerOfTwo(alignment));
intptr_t pos = offset + buffer_.GetPosition();
@@ -2663,21 +2680,30 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
Label* trace,
- bool near_jump) {
+ bool near_jump,
+ bool inline_isolate) {
ASSERT(cid > 0);
Address state_address(kNoRegister, 0);
- intptr_t state_offset;
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr =
- class_table->StateAddressFor(cid, &state_offset);
- if (cid < kNumPredefinedCids) {
- state_address = Address::Absolute(
- reinterpret_cast<uword>(*table_ptr) + state_offset);
+ 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);
- // temp_reg gets address of class table pointer.
- movl(temp_reg,
- Address::Absolute(reinterpret_cast<uword>(table_ptr)));
+ 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()));
@@ -2763,23 +2789,26 @@
Register instance_reg,
Register temp_reg) {
ASSERT(failure != NULL);
+ ASSERT(temp_reg != kNoRegister);
if (FLAG_inline_alloc) {
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cls.id(), temp_reg, failure, near_jump);
- Heap* heap = Isolate::Current()->heap();
+ MaybeTraceAllocation(cls.id(), temp_reg, failure, near_jump,
+ /* inline_isolate = */ false);
const intptr_t instance_size = cls.instance_size();
- Heap::Space space = heap->SpaceForAllocation(cls.id());
- movl(instance_reg, Address::Absolute(heap->TopAddress(space)));
+ Heap::Space space = Heap::SpaceForAllocation(cls.id());
+ movl(temp_reg, Address(THR, Thread::heap_offset()));
+ movl(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
addl(instance_reg, Immediate(instance_size));
// instance_reg: potential next object start.
- cmpl(instance_reg, Address::Absolute(heap->EndAddress(space)));
+ cmpl(instance_reg, Address(temp_reg, Heap::EndOffset(space)));
j(ABOVE_EQUAL, failure, near_jump);
// 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::Absolute(heap->TopAddress(space)), instance_reg);
- UpdateAllocationStats(cls.id(), temp_reg, space);
+ movl(Address(temp_reg, Heap::TopOffset(space)), instance_reg);
+ UpdateAllocationStats(cls.id(), temp_reg, space,
+ /* inline_isolate = */ false);
ASSERT(instance_size >= kHeapObjectTag);
subl(instance_reg, Immediate(instance_size - kHeapObjectTag));
uword tags = 0;
@@ -2798,17 +2827,19 @@
Label* failure,
bool near_jump,
Register instance,
- Register end_address) {
+ Register end_address,
+ Register temp_reg) {
ASSERT(failure != NULL);
+ ASSERT(temp_reg != kNoRegister);
if (FLAG_inline_alloc) {
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cid, kNoRegister, failure, near_jump);
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
- Heap::Space space = heap->SpaceForAllocation(cid);
- movl(instance, Address::Absolute(heap->TopAddress(space)));
+ MaybeTraceAllocation(cid, temp_reg, failure, near_jump,
+ /* inline_isolate = */ false);
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ movl(temp_reg, Address(THR, Thread::heap_offset()));
+ movl(instance, Address(temp_reg, Heap::TopOffset(space)));
movl(end_address, instance);
addl(end_address, Immediate(instance_size));
@@ -2817,14 +2848,15 @@
// Check if the allocation fits into the remaining space.
// EAX: potential new object start.
// EBX: potential next object start.
- cmpl(end_address, Address::Absolute(heap->EndAddress(space)));
+ cmpl(end_address, Address(temp_reg, Heap::EndOffset(space)));
j(ABOVE_EQUAL, failure);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- movl(Address::Absolute(heap->TopAddress(space)), end_address);
+ movl(Address(temp_reg, Heap::TopOffset(space)), end_address);
addl(instance, Immediate(kHeapObjectTag));
- UpdateAllocationStatsWithSize(cid, instance_size, kNoRegister, space);
+ UpdateAllocationStatsWithSize(cid, instance_size, temp_reg, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
uword tags = 0;
@@ -2891,10 +2923,9 @@
void Assembler::Stop(const char* message) {
if (FLAG_print_stop_message) {
- StubCode* stub_code = Isolate::Current()->stub_code();
pushl(EAX); // Preserve EAX.
movl(EAX, Immediate(reinterpret_cast<int32_t>(message)));
- call(&stub_code->PrintStopMessageLabel()); // Passing message in EAX.
+ Call(*StubCode::PrintStopMessage_entry()); // Passing message in EAX.
popl(EAX); // Restore EAX.
} else {
// Emit the message address as immediate operand in the test instruction.
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 909ebda..bac86c4 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -17,6 +17,7 @@
// Forward declarations.
class RuntimeEntry;
+class StubEntry;
class Immediate : public ValueObject {
public:
@@ -731,6 +732,11 @@
void CallRuntime(const RuntimeEntry& entry, intptr_t argument_count);
+ void Call(const StubEntry& stub_entry);
+
+ void Jmp(const StubEntry& stub_entry);
+ void J(Condition condition, const StubEntry& stub_entry);
+
/*
* Loading and comparing classes of objects.
*/
@@ -876,7 +882,8 @@
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
Label* trace,
- bool near_jump);
+ bool near_jump,
+ bool inline_isolate = true);
void UpdateAllocationStats(intptr_t cid,
Register temp_reg,
@@ -909,7 +916,8 @@
Label* failure,
bool near_jump,
Register instance,
- Register end_address);
+ Register end_address,
+ Register temp);
// Debugging and bringup support.
void Stop(const char* message);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index cb65f35..e4f9082 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -355,7 +355,7 @@
void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) {
- ASSERT(allow_constant_pool());
+ ASSERT(constant_pool_allowed());
ASSERT(!in_delay_slot_);
ASSERT(rd != PP);
if (Address::CanHoldOffset(offset)) {
@@ -456,6 +456,37 @@
}
+void Assembler::Branch(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ Branch(&label);
+}
+
+
+void Assembler::BranchPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchPatchable(&label);
+}
+
+
+void Assembler::BranchLink(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLink(&label);
+}
+
+
+void Assembler::BranchLink(const StubEntry& stub_entry,
+ Patchability patchable) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLink(&label, patchable);
+}
+
+
+void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ BranchLink(&label, kPatchable);
+}
+
+
void Assembler::LoadObjectHelper(Register rd,
const Object& object,
bool is_unique) {
@@ -469,7 +500,7 @@
// Smis and VM heap objects are never relocated; do not use object pool.
if (object.IsSmi()) {
LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()));
- } else if (object.InVMHeap() || !allow_constant_pool()) {
+ } else if (object.InVMHeap() || !constant_pool_allowed()) {
// 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);
@@ -885,20 +916,29 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace) {
+ Label* trace,
+ bool inline_isolate) {
ASSERT(cid > 0);
ASSERT(!in_delay_slot_);
ASSERT(temp_reg != kNoRegister);
ASSERT(temp_reg != TMP);
- intptr_t state_offset;
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr =
- class_table->StateAddressFor(cid, &state_offset);
- if (cid < kNumPredefinedCids) {
- LoadImmediate(temp_reg, reinterpret_cast<uword>(*table_ptr) + state_offset);
+ 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) {
+ 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 {
- LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr));
- lw(temp_reg, Address(temp_reg, 0));
+ 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));
@@ -917,30 +957,28 @@
// 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);
+ MaybeTraceAllocation(cls.id(), temp_reg, failure,
+ /* inline_isolate = */ false);
const intptr_t instance_size = cls.instance_size();
- Heap* heap = Isolate::Current()->heap();
- Heap::Space space = heap->SpaceForAllocation(cls.id());
- const uword top_address = heap->TopAddress(space);
- LoadImmediate(temp_reg, top_address);
- lw(instance_reg, Address(temp_reg));
+ Heap::Space space = Heap::SpaceForAllocation(cls.id());
+ lw(temp_reg, Address(THR, Thread::heap_offset()));
+ lw(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
// TODO(koda): Protect against unsigned overflow here.
AddImmediate(instance_reg, instance_size);
// instance_reg: potential next object start.
- const uword end_address = heap->EndAddress(space);
- ASSERT(top_address < end_address);
- lw(TMP, Address(temp_reg, end_address - top_address));
+ lw(TMP, Address(temp_reg, Heap::EndOffset(space)));
// Fail if heap end unsigned less than or equal to instance_reg.
BranchUnsignedLessEqual(TMP, instance_reg, failure);
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
- sw(instance_reg, Address(temp_reg));
+ sw(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
- UpdateAllocationStats(cls.id(), temp_reg, space);
+ UpdateAllocationStats(cls.id(), temp_reg, space,
+ /* inline_isolate = */ false);
uword tags = 0;
tags = RawObject::SizeTag::update(instance_size, tags);
ASSERT(cls.id() != kIllegalCid);
@@ -968,27 +1006,27 @@
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
Heap::Space space = heap->SpaceForAllocation(cid);
- LoadImmediate(temp1, heap->TopAddress(space));
- lw(instance, Address(temp1, 0)); // Potential new object start.
+ lw(temp1, Address(THR, Thread::heap_offset()));
+ // Potential new object start.
+ lw(instance, Address(temp1, heap->TopOffset(space)));
// Potential next object start.
AddImmediate(end_address, instance, instance_size);
// Branch on unsigned overflow.
BranchUnsignedLess(end_address, instance, failure);
// Check if the allocation fits into the remaining space.
- // instance: potential new object start.
+ // instance: potential new object start, /* inline_isolate = */ false.
// end_address: potential next object start.
- LoadImmediate(temp2, heap->EndAddress(space));
- lw(temp2, Address(temp2, 0));
+ lw(temp2, Address(temp1, Heap::EndOffset(space)));
BranchUnsignedGreaterEqual(end_address, temp2, failure);
-
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- sw(end_address, Address(temp1, 0));
+ sw(end_address, Address(temp1, Heap::TopOffset(space)));
addiu(instance, instance, Immediate(kHeapObjectTag));
LoadImmediate(temp1, instance_size);
- UpdateAllocationStatsWithSize(cid, temp1, temp2, space);
+ UpdateAllocationStatsWithSize(cid, temp1, temp2, space,
+ /* inline_isolate = */ false);
// 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 174ec9f..0f0897f 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -26,6 +26,7 @@
// Forward declarations.
class RuntimeEntry;
+class StubEntry;
class Immediate : public ValueObject {
public:
@@ -241,7 +242,7 @@
delay_slot_available_(false),
in_delay_slot_(false),
comments_(),
- allow_constant_pool_(true) { }
+ constant_pool_allowed_(true) { }
~Assembler() { }
void PopRegister(Register r) { Pop(r); }
@@ -316,7 +317,8 @@
void MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
- Label* trace);
+ Label* trace,
+ bool inline_isolate = true);
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
@@ -916,6 +918,8 @@
jr(TMP);
}
+ void Branch(const StubEntry& stub_entry);
+
void BranchPatchable(const ExternalLabel* label) {
ASSERT(!in_delay_slot_);
const uint16_t low = Utils::Low16Bits(label->address());
@@ -926,12 +930,16 @@
delay_slot_available_ = false; // CodePatcher expects a nop.
}
+ void BranchPatchable(const StubEntry& stub_entry);
+
void BranchLink(const ExternalLabel* label) {
ASSERT(!in_delay_slot_);
LoadImmediate(T9, label->address());
jalr(T9);
}
+ void BranchLink(const StubEntry& stub_entry);
+
void BranchLink(const ExternalLabel* label, Patchability patchable) {
ASSERT(!in_delay_slot_);
const int32_t offset = ObjectPool::element_offset(
@@ -943,10 +951,14 @@
}
}
+ void BranchLink(const StubEntry& stub_entry, Patchability patchable);
+
void BranchLinkPatchable(const ExternalLabel* label) {
BranchLink(label, kPatchable);
}
+ void BranchLinkPatchable(const StubEntry& stub_entry);
+
void Drop(intptr_t stack_elements) {
ASSERT(stack_elements >= 0);
if (stack_elements > 0) {
@@ -1622,11 +1634,11 @@
static bool IsSafe(const Object& object) { return true; }
static bool IsSafeSmi(const Object& object) { return object.IsSmi(); }
- bool allow_constant_pool() const {
- return allow_constant_pool_;
+ bool constant_pool_allowed() const {
+ return constant_pool_allowed_;
}
- void set_allow_constant_pool(bool b) {
- allow_constant_pool_ = b;
+ void set_constant_pool_allowed(bool b) {
+ constant_pool_allowed_ = b;
}
private:
@@ -1656,7 +1668,7 @@
GrowableArray<CodeComment*> comments_;
- bool allow_constant_pool_;
+ bool constant_pool_allowed_;
void LoadObjectHelper(Register rd, const Object& object, bool is_unique);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 48118d5..fd27c9a 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -25,7 +25,7 @@
: buffer_(),
prologue_offset_(-1),
comments_(),
- allow_constant_pool_(true) {
+ constant_pool_allowed_(false) {
// Far branching mode is only needed and implemented for MIPS and ARM.
ASSERT(!use_far_branches);
}
@@ -63,11 +63,10 @@
void Assembler::LoadExternalLabel(Register dst,
const ExternalLabel* label,
- Patchability patchable,
- Register pp) {
+ Patchability patchable) {
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, patchable));
- LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
+ LoadWordFromPoolOffset(dst, offset - kHeapObjectTag);
}
@@ -83,7 +82,7 @@
void Assembler::CallPatchable(const ExternalLabel* label) {
- ASSERT(allow_constant_pool());
+ ASSERT(constant_pool_allowed());
intptr_t call_start = buffer_.GetPosition();
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, kPatchable));
@@ -92,10 +91,23 @@
}
-void Assembler::Call(const ExternalLabel* label, Register pp) {
+void Assembler::Call(const ExternalLabel* label) {
+ ASSERT(constant_pool_allowed());
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, kNotPatchable));
- call(Address::AddressBaseImm32(pp, offset - kHeapObjectTag));
+ call(Address::AddressBaseImm32(PP, offset - kHeapObjectTag));
+}
+
+
+void Assembler::CallPatchable(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ CallPatchable(&label);
+}
+
+
+void Assembler::Call(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ Call(&label);
}
@@ -126,12 +138,12 @@
}
-void Assembler::PushImmediate(const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- LoadImmediate(TMP, imm, pp);
- pushq(TMP);
- } else {
+void Assembler::PushImmediate(const Immediate& imm) {
+ if (imm.is_int32()) {
pushq(imm);
+ } else {
+ LoadImmediate(TMP, imm);
+ pushq(TMP);
}
}
@@ -782,7 +794,7 @@
} float_not_constant =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)));
xorps(dst, Address(TMP, 0));
}
@@ -796,7 +808,7 @@
} float_negate_constant =
{ 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)));
xorps(dst, Address(TMP, 0));
}
@@ -810,7 +822,7 @@
} float_absolute_constant =
{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)));
andps(dst, Address(TMP, 0));
}
@@ -824,7 +836,7 @@
} float_zerow_constant =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)));
andps(dst, Address(TMP, 0));
}
@@ -1012,7 +1024,7 @@
} double_negate_constant =
{ 0x8000000000000000LL, 0x8000000000000000LL };
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
xorpd(dst, Address(TMP, 0));
}
@@ -1060,7 +1072,7 @@
} double_absolute_const =
{ 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL };
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&double_absolute_const)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&double_absolute_const)));
andpd(dst, Address(TMP, 0));
}
@@ -1473,6 +1485,7 @@
EmitRegisterREX(reg, REX_W);
EmitComplex(7, Operand(reg), imm);
} else {
+ ASSERT(reg != TMP);
movq(TMP, imm);
cmpq(reg, TMP);
}
@@ -1496,24 +1509,23 @@
}
-void Assembler::CompareImmediate(Register reg, const Immediate& imm,
- Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- LoadImmediate(TMP, imm, pp);
- cmpq(reg, TMP);
- } else {
+void Assembler::CompareImmediate(Register reg, const Immediate& imm) {
+ if (imm.is_int32()) {
cmpq(reg, imm);
+ } else {
+ ASSERT(reg != TMP);
+ LoadImmediate(TMP, imm);
+ cmpq(reg, TMP);
}
}
-void Assembler::CompareImmediate(const Address& address, const Immediate& imm,
- Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- LoadImmediate(TMP, imm, pp);
- cmpq(address, TMP);
- } else {
+void Assembler::CompareImmediate(const Address& address, const Immediate& imm) {
+ if (imm.is_int32()) {
cmpq(address, imm);
+ } else {
+ LoadImmediate(TMP, imm);
+ cmpq(address, TMP);
}
}
@@ -1608,13 +1620,13 @@
}
-void Assembler::TestImmediate(Register dst, const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(dst != TMP);
- LoadImmediate(TMP, imm, pp);
- testq(dst, TMP);
- } else {
+void Assembler::TestImmediate(Register dst, const Immediate& imm) {
+ if (imm.is_int32()) {
testq(dst, imm);
+ } else {
+ ASSERT(dst != TMP);
+ LoadImmediate(TMP, imm);
+ testq(dst, TMP);
}
}
@@ -1691,19 +1703,20 @@
EmitRegisterREX(dst, REX_W);
EmitComplex(4, Operand(dst), imm);
} else {
+ ASSERT(dst != TMP);
movq(TMP, imm);
andq(dst, TMP);
}
}
-void Assembler::AndImmediate(Register dst, const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(dst != TMP);
- LoadImmediate(TMP, imm, pp);
- andq(dst, TMP);
- } else {
+void Assembler::AndImmediate(Register dst, const Immediate& imm) {
+ if (imm.is_int32()) {
andq(dst, imm);
+ } else {
+ ASSERT(dst != TMP);
+ LoadImmediate(TMP, imm);
+ andq(dst, TMP);
}
}
@@ -1731,19 +1744,20 @@
EmitRegisterREX(dst, REX_W);
EmitComplex(1, Operand(dst), imm);
} else {
+ ASSERT(dst != TMP);
movq(TMP, imm);
orq(dst, TMP);
}
}
-void Assembler::OrImmediate(Register dst, const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(dst != TMP);
- LoadImmediate(TMP, imm, pp);
- orq(dst, TMP);
- } else {
+void Assembler::OrImmediate(Register dst, const Immediate& imm) {
+ if (imm.is_int32()) {
orq(dst, imm);
+ } else {
+ ASSERT(dst != TMP);
+ LoadImmediate(TMP, imm);
+ orq(dst, TMP);
}
}
@@ -1779,19 +1793,20 @@
EmitRegisterREX(dst, REX_W);
EmitComplex(6, Operand(dst), imm);
} else {
+ ASSERT(dst != TMP);
movq(TMP, imm);
xorq(dst, TMP);
}
}
-void Assembler::XorImmediate(Register dst, const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(dst != TMP);
- LoadImmediate(TMP, imm, pp);
- xorq(dst, TMP);
- } else {
+void Assembler::XorImmediate(Register dst, const Immediate& imm) {
+ if (imm.is_int32()) {
xorq(dst, imm);
+ } else {
+ ASSERT(dst != TMP);
+ LoadImmediate(TMP, imm);
+ xorq(dst, TMP);
}
}
@@ -1877,6 +1892,7 @@
EmitRegisterREX(dst, REX_W);
EmitComplex(0, Operand(dst), imm);
} else {
+ ASSERT(dst != TMP);
movq(TMP, imm);
addq(dst, TMP);
}
@@ -1918,6 +1934,7 @@
EmitRegisterREX(dst, REX_W);
EmitComplex(2, Operand(dst), imm);
} else {
+ ASSERT(dst != TMP);
movq(TMP, imm);
adcq(dst, TMP);
}
@@ -2074,19 +2091,20 @@
EmitOperand(reg & 7, Operand(reg));
EmitImmediate(imm);
} else {
+ ASSERT(reg != TMP);
movq(TMP, imm);
imulq(reg, TMP);
}
}
-void Assembler::MulImmediate(Register reg, const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(reg != TMP);
- LoadImmediate(TMP, imm, pp);
- imulq(reg, TMP);
- } else {
+void Assembler::MulImmediate(Register reg, const Immediate& imm) {
+ if (imm.is_int32()) {
imulq(reg, imm);
+ } else {
+ ASSERT(reg != TMP);
+ LoadImmediate(TMP, imm);
+ imulq(reg, TMP);
}
}
@@ -2123,6 +2141,7 @@
EmitRegisterREX(reg, REX_W);
EmitComplex(5, Operand(reg), imm);
} else {
+ ASSERT(reg != TMP);
movq(TMP, imm);
subq(reg, TMP);
}
@@ -2172,6 +2191,7 @@
EmitRegisterREX(dst, REX_W);
EmitComplex(3, Operand(dst), imm);
} else {
+ ASSERT(dst != TMP);
movq(TMP, imm);
sbbq(dst, TMP);
}
@@ -2543,6 +2563,13 @@
}
+void Assembler::J(Condition condition, const StubEntry& stub_entry,
+ Register pp) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ J(condition, &label, pp);
+}
+
+
void Assembler::jmp(Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(reg);
@@ -2598,8 +2625,14 @@
}
+void Assembler::jmp(const StubEntry& stub_entry) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ jmp(&label);
+}
+
+
void Assembler::JmpPatchable(const ExternalLabel* label, Register pp) {
- ASSERT(allow_constant_pool());
+ ASSERT((pp != PP) || constant_pool_allowed());
intptr_t call_start = buffer_.GetPosition();
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, kPatchable));
@@ -2609,13 +2642,26 @@
}
+void Assembler::JmpPatchable(const StubEntry& stub_entry, Register pp) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ JmpPatchable(&label, pp);
+}
+
+
void Assembler::Jmp(const ExternalLabel* label, Register pp) {
+ ASSERT((pp != PP) || constant_pool_allowed());
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper_.FindExternalLabel(label, kNotPatchable));
jmp(Address(pp, offset - kHeapObjectTag));
}
+void Assembler::Jmp(const StubEntry& stub_entry, Register pp) {
+ const ExternalLabel label(stub_entry.EntryPoint());
+ Jmp(&label, pp);
+}
+
+
void Assembler::lock() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF0);
@@ -2664,7 +2710,7 @@
}
-void Assembler::AddImmediate(Register reg, const Immediate& imm, Register pp) {
+void Assembler::AddImmediate(Register reg, const Immediate& imm) {
const int64_t value = imm.value();
if (value == 0) {
return;
@@ -2673,22 +2719,21 @@
if (value == 1) {
incq(reg);
} else {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(reg != TMP);
- LoadImmediate(TMP, imm, pp);
- addq(reg, TMP);
- } else {
+ if (imm.is_int32()) {
addq(reg, imm);
+ } else {
+ ASSERT(reg != TMP);
+ LoadImmediate(TMP, imm);
+ addq(reg, TMP);
}
}
} else {
- SubImmediate(reg, Immediate(-value), pp);
+ SubImmediate(reg, Immediate(-value));
}
}
-void Assembler::AddImmediate(const Address& address, const Immediate& imm,
- Register pp) {
+void Assembler::AddImmediate(const Address& address, const Immediate& imm) {
const int64_t value = imm.value();
if (value == 0) {
return;
@@ -2697,20 +2742,20 @@
if (value == 1) {
incq(address);
} else {
- if (CanLoadImmediateFromPool(imm, pp)) {
- LoadImmediate(TMP, imm, pp);
- addq(address, TMP);
- } else {
+ if (imm.is_int32()) {
addq(address, imm);
+ } else {
+ LoadImmediate(TMP, imm);
+ addq(address, TMP);
}
}
} else {
- SubImmediate(address, Immediate(-value), pp);
+ SubImmediate(address, Immediate(-value));
}
}
-void Assembler::SubImmediate(Register reg, const Immediate& imm, Register pp) {
+void Assembler::SubImmediate(Register reg, const Immediate& imm) {
const int64_t value = imm.value();
if (value == 0) {
return;
@@ -2719,22 +2764,21 @@
if (value == 1) {
decq(reg);
} else {
- if (CanLoadImmediateFromPool(imm, pp)) {
- ASSERT(reg != TMP);
- LoadImmediate(TMP, imm, pp);
- subq(reg, TMP);
- } else {
+ if (imm.is_int32()) {
subq(reg, imm);
+ } else {
+ ASSERT(reg != TMP);
+ LoadImmediate(TMP, imm);
+ subq(reg, TMP);
}
}
} else {
- AddImmediate(reg, Immediate(-value), pp);
+ AddImmediate(reg, Immediate(-value));
}
}
-void Assembler::SubImmediate(const Address& address, const Immediate& imm,
- Register pp) {
+void Assembler::SubImmediate(const Address& address, const Immediate& imm) {
const int64_t value = imm.value();
if (value == 0) {
return;
@@ -2743,15 +2787,15 @@
if (value == 1) {
decq(address);
} else {
- if (CanLoadImmediateFromPool(imm, pp)) {
- LoadImmediate(TMP, imm, pp);
- subq(address, TMP);
- } else {
+ if (imm.is_int32()) {
subq(address, imm);
+ } else {
+ LoadImmediate(TMP, imm);
+ subq(address, TMP);
}
}
} else {
- AddImmediate(address, Immediate(-value), pp);
+ AddImmediate(address, Immediate(-value));
}
}
@@ -2770,7 +2814,7 @@
bool Assembler::CanLoadFromObjectPool(const Object& object) const {
ASSERT(!Thread::CanLoadFromThread(object));
- if (!allow_constant_pool()) {
+ if (!constant_pool_allowed()) {
return false;
}
@@ -2787,11 +2831,12 @@
}
-void Assembler::LoadWordFromPoolOffset(Register dst, Register pp,
- int32_t offset) {
+void Assembler::LoadWordFromPoolOffset(Register dst, int32_t offset) {
+ ASSERT(constant_pool_allowed());
+ ASSERT(dst != PP);
// This sequence must be of fixed size. AddressBaseImm32
// forces the address operand to use a fixed-size imm32 encoding.
- movq(dst, Address::AddressBaseImm32(pp, offset));
+ movq(dst, Address::AddressBaseImm32(PP, offset));
}
@@ -2802,7 +2847,6 @@
void Assembler::LoadObjectHelper(Register dst,
const Object& object,
- Register pp,
bool is_unique) {
if (Thread::CanLoadFromThread(object)) {
movq(dst, Address(THR, Thread::OffsetFromThread(object)));
@@ -2810,62 +2854,70 @@
const int32_t offset = ObjectPool::element_offset(
is_unique ? object_pool_wrapper_.AddObject(object)
: object_pool_wrapper_.FindObject(object));
- LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
+ LoadWordFromPoolOffset(dst, offset - kHeapObjectTag);
} else {
ASSERT(object.IsSmi() || object.InVMHeap());
- LoadImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())), pp);
+ LoadImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
-void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
- LoadObjectHelper(dst, object, pp, false);
+void Assembler::LoadFunctionFromCalleePool(Register dst,
+ const Function& function,
+ Register new_pp) {
+ ASSERT(!constant_pool_allowed());
+ ASSERT(new_pp != PP);
+ const int32_t offset =
+ ObjectPool::element_offset(object_pool_wrapper_.FindObject(function));
+ movq(dst, Address::AddressBaseImm32(new_pp, offset - kHeapObjectTag));
}
-void Assembler::LoadUniqueObject(Register dst,
- const Object& object,
- Register pp) {
- LoadObjectHelper(dst, object, pp, true);
+void Assembler::LoadObject(Register dst, const Object& object) {
+ LoadObjectHelper(dst, object, false);
}
-void Assembler::StoreObject(const Address& dst, const Object& object,
- Register pp) {
+void Assembler::LoadUniqueObject(Register dst, const Object& object) {
+ LoadObjectHelper(dst, object, true);
+}
+
+
+void Assembler::StoreObject(const Address& dst, const Object& object) {
if (Thread::CanLoadFromThread(object)) {
movq(TMP, Address(THR, Thread::OffsetFromThread(object)));
movq(dst, TMP);
} else if (CanLoadFromObjectPool(object)) {
- LoadObject(TMP, object, pp);
+ LoadObject(TMP, object);
movq(dst, TMP);
} else {
- MoveImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())), pp);
+ MoveImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
-void Assembler::PushObject(const Object& object, Register pp) {
+void Assembler::PushObject(const Object& object) {
if (Thread::CanLoadFromThread(object)) {
pushq(Address(THR, Thread::OffsetFromThread(object)));
} else if (CanLoadFromObjectPool(object)) {
- LoadObject(TMP, object, pp);
+ LoadObject(TMP, object);
pushq(TMP);
} else {
- PushImmediate(Immediate(reinterpret_cast<int64_t>(object.raw())), pp);
+ PushImmediate(Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
-void Assembler::CompareObject(Register reg, const Object& object, Register pp) {
+void Assembler::CompareObject(Register reg, const Object& object) {
if (Thread::CanLoadFromThread(object)) {
cmpq(reg, Address(THR, Thread::OffsetFromThread(object)));
} else if (CanLoadFromObjectPool(object)) {
const int32_t offset =
ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
- cmpq(reg, Address(pp, offset-kHeapObjectTag));
+ cmpq(reg, Address(PP, offset-kHeapObjectTag));
} else {
CompareImmediate(
- reg, Immediate(reinterpret_cast<int64_t>(object.raw())), pp);
+ reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
@@ -2875,33 +2927,22 @@
}
-bool Assembler::CanLoadImmediateFromPool(const Immediate& imm, Register pp) {
- if (!allow_constant_pool()) {
- return false;
- }
- return !imm.is_int32() && (pp != kNoRegister);
-}
-
-
-void Assembler::LoadImmediate(Register reg, const Immediate& imm, Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- // It's a 64-bit constant and we're not in the VM isolate, so load from
- // object pool.
- int32_t offset = ObjectPool::element_offset(FindImmediate(imm.value()));
- LoadWordFromPoolOffset(reg, pp, offset - kHeapObjectTag);
- } else {
+void Assembler::LoadImmediate(Register reg, const Immediate& imm) {
+ if (imm.is_int32() || !constant_pool_allowed()) {
movq(reg, imm);
+ } else {
+ int32_t offset = ObjectPool::element_offset(FindImmediate(imm.value()));
+ LoadWordFromPoolOffset(reg, offset - kHeapObjectTag);
}
}
-void Assembler::MoveImmediate(const Address& dst, const Immediate& imm,
- Register pp) {
- if (CanLoadImmediateFromPool(imm, pp)) {
- LoadImmediate(TMP, imm, pp);
- movq(dst, TMP);
- } else {
+void Assembler::MoveImmediate(const Address& dst, const Immediate& imm) {
+ if (imm.is_int32()) {
movq(dst, imm);
+ } else {
+ LoadImmediate(TMP, imm);
+ movq(dst, TMP);
}
}
@@ -3087,18 +3128,17 @@
void Assembler::StoreIntoObjectNoBarrier(Register object,
const Address& dest,
const Object& value,
- Register pp,
FieldContent old_content) {
VerifyHeapWord(dest, old_content);
if (VerifiedMemory::enabled()) {
- Register temp = (pp == RCX) ? RDX : RCX;
+ const Register temp = RCX;
pushq(temp);
leaq(temp, dest);
- StoreObject(Address(temp, 0), value, pp);
- StoreObject(Address(temp, VerifiedMemory::offset()), value, pp);
+ StoreObject(Address(temp, 0), value);
+ StoreObject(Address(temp, VerifiedMemory::offset()), value);
popq(temp);
} else {
- StoreObject(dest, value, pp);
+ StoreObject(dest, value);
}
// TODO(koda): Use 'object', verify that generational barrier's not needed.
}
@@ -3155,7 +3195,7 @@
} double_negate_constant =
{0x8000000000000000LL, 0x8000000000000000LL};
LoadImmediate(
- TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)), PP);
+ TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
xorpd(d, Address(TMP, 0));
}
@@ -3167,7 +3207,7 @@
} double_abs_constant =
{0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
LoadImmediate(TMP,
- Immediate(reinterpret_cast<intptr_t>(&double_abs_constant)), PP);
+ Immediate(reinterpret_cast<intptr_t>(&double_abs_constant)));
andpd(reg, Address(TMP, 0));
}
@@ -3183,9 +3223,9 @@
EmitUint8(0xB8 | (RDI & 7));
EmitInt64(message_address);
} else {
- LoadImmediate(RDI, Immediate(message_address), PP);
+ LoadImmediate(RDI, Immediate(message_address));
}
- call(&Isolate::Current()->stub_code()->PrintStopMessageLabel());
+ call(&StubCode::PrintStopMessage_entry()->label());
popq(RDI); // Restore RDI register.
popq(TMP); // Restore TMP register.
} else {
@@ -3261,7 +3301,7 @@
intptr_t xmm_register_set) {
const intptr_t xmm_regs_count = RegisterSet::RegisterCount(xmm_register_set);
if (xmm_regs_count > 0) {
- AddImmediate(RSP, Immediate(-xmm_regs_count * kFpuRegisterSize), PP);
+ AddImmediate(RSP, Immediate(-xmm_regs_count * kFpuRegisterSize));
// Store XMM registers with the lowest register number at the lowest
// address.
intptr_t offset = 0;
@@ -3310,7 +3350,7 @@
}
}
ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
- AddImmediate(RSP, Immediate(offset), PP);
+ AddImmediate(RSP, Immediate(offset));
}
}
@@ -3380,16 +3420,19 @@
movq(pp, Address::AddressRIPRelative(
-entry_to_rip_offset - object_pool_pc_dist));
ASSERT(CodeSize() == entry_to_rip_offset);
+ set_constant_pool_allowed(pp == PP);
}
void Assembler::EnterDartFrameWithInfo(intptr_t frame_size,
Register new_pp,
Register pc_marker_override) {
+ ASSERT(!constant_pool_allowed());
EnterFrame(0);
pushq(pc_marker_override);
pushq(PP);
movq(PP, new_pp);
+ set_constant_pool_allowed(true);
if (frame_size != 0) {
subq(RSP, Immediate(frame_size));
}
@@ -3397,6 +3440,10 @@
void Assembler::LeaveDartFrame() {
+ // LeaveDartFrame is called from stubs (pp disallowed) and from Dart code (pp
+ // allowed), so there is no point in checking the current value of
+ // constant_pool_allowed().
+ set_constant_pool_allowed(false);
// Restore caller's PP register that was pushed in EnterDartFrame.
movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize)));
LeaveFrame();
@@ -3411,12 +3458,14 @@
void Assembler::EnterOsrFrame(intptr_t extra_size,
Register new_pp,
Register pc_marker_override) {
+ ASSERT(!constant_pool_allowed());
if (prologue_offset_ == -1) {
Comment("PrologueOffset = %" Pd "", CodeSize());
prologue_offset_ = CodeSize();
}
movq(Address(RBP, kPcMarkerSlotFromFp * kWordSize), pc_marker_override);
movq(PP, new_pp);
+ set_constant_pool_allowed(true);
if (extra_size != 0) {
subq(RSP, Immediate(extra_size));
}
@@ -3424,14 +3473,16 @@
void Assembler::EnterStubFrame() {
+ set_constant_pool_allowed(false);
EnterFrame(0);
pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames.
pushq(PP); // Save caller's pool pointer
- LoadPoolPointer(PP);
+ LoadPoolPointer();
}
void Assembler::LeaveStubFrame() {
+ set_constant_pool_allowed(false);
// Restore caller's PP register that was pushed in EnterStubFrame.
movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize)));
LeaveFrame();
@@ -3440,19 +3491,25 @@
void Assembler::MaybeTraceAllocation(intptr_t cid,
Label* trace,
- bool near_jump) {
+ bool near_jump,
+ bool inline_isolate) {
ASSERT(cid > 0);
- intptr_t state_offset;
- ClassTable* class_table = Isolate::Current()->class_table();
- ClassHeapStats** table_ptr =
- class_table->StateAddressFor(cid, &state_offset);
+ intptr_t state_offset = ClassTable::StateOffsetFor(cid);
Register temp_reg = TMP;
- if (cid < kNumPredefinedCids) {
- movq(temp_reg, Immediate(reinterpret_cast<uword>(*table_ptr)));
+ if (inline_isolate) {
+ 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 {
- Register temp_reg = TMP;
- movq(temp_reg, Immediate(reinterpret_cast<uword>(table_ptr)));
- movq(temp_reg, Address(temp_reg, 0));
+ 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()));
@@ -3518,36 +3575,34 @@
Label* failure,
bool near_jump,
Register instance_reg,
- Register pp) {
+ Register temp) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cls.id(), failure, near_jump);
- Heap* heap = Isolate::Current()->heap();
+ MaybeTraceAllocation(cls.id(), failure, near_jump,
+ /* inline_isolate = */ false);
const intptr_t instance_size = cls.instance_size();
- Heap::Space space = heap->SpaceForAllocation(cls.id());
- LoadImmediate(TMP, Immediate(heap->TopAddress(space)), pp);
- movq(instance_reg, Address(TMP, 0));
- AddImmediate(instance_reg, Immediate(instance_size), pp);
+ Heap::Space space = Heap::SpaceForAllocation(cls.id());
+ movq(temp, Address(THR, Thread::heap_offset()));
+ movq(instance_reg, Address(temp, Heap::TopOffset(space)));
+ addq(instance_reg, Immediate(instance_size));
// instance_reg: potential next object start.
- LoadImmediate(TMP, Immediate(heap->EndAddress(space)), pp);
- cmpq(instance_reg, Address(TMP, 0));
+ cmpq(instance_reg, Address(temp, Heap::EndOffset(space)));
j(ABOVE_EQUAL, failure, near_jump);
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
- LoadImmediate(TMP, Immediate(heap->TopAddress(space)), pp);
- movq(Address(TMP, 0), instance_reg);
- UpdateAllocationStats(cls.id(), space);
+ movq(Address(temp, Heap::TopOffset(space)), instance_reg);
+ UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
ASSERT(instance_size >= kHeapObjectTag);
- AddImmediate(instance_reg, Immediate(kHeapObjectTag - instance_size), pp);
+ AddImmediate(instance_reg, Immediate(kHeapObjectTag - instance_size));
uword tags = 0;
tags = RawObject::SizeTag::update(instance_size, tags);
ASSERT(cls.id() != kIllegalCid);
tags = RawObject::ClassIdTag::update(cls.id(), tags);
MoveImmediate(FieldAddress(instance_reg, Object::tags_offset()),
- Immediate(tags), pp);
+ Immediate(tags));
} else {
jmp(failure);
}
@@ -3559,19 +3614,18 @@
Label* failure,
bool near_jump,
Register instance,
- Register end_address) {
+ Register end_address,
+ Register temp) {
ASSERT(failure != NULL);
if (FLAG_inline_alloc) {
// If this allocation is traced, program will jump to failure path
// (i.e. the allocation stub) which will allocate the object and trace the
// allocation call site.
- MaybeTraceAllocation(cid, failure, near_jump);
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
- Heap::Space space = heap->SpaceForAllocation(cid);
- movq(instance, Immediate(heap->TopAddress(space)));
- movq(instance, Address(instance, 0));
- movq(end_address, RAX);
+ MaybeTraceAllocation(cid, failure, near_jump, /* inline_isolate = */ false);
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ movq(temp, Address(THR, Thread::heap_offset()));
+ movq(instance, Address(temp, Heap::TopOffset(space)));
+ movq(end_address, instance);
addq(end_address, Immediate(instance_size));
j(CARRY, failure);
@@ -3579,16 +3633,15 @@
// Check if the allocation fits into the remaining space.
// instance: potential new object start.
// end_address: potential next object start.
- movq(TMP, Immediate(heap->EndAddress(space)));
- cmpq(end_address, Address(TMP, 0));
+ cmpq(end_address, Address(temp, Heap::EndOffset(space)));
j(ABOVE_EQUAL, failure);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- movq(TMP, Immediate(heap->TopAddress(space)));
- movq(Address(TMP, 0), end_address);
+ movq(Address(temp, Heap::TopOffset(space)), end_address);
addq(instance, Immediate(kHeapObjectTag));
- UpdateAllocationStatsWithSize(cid, instance_size, space);
+ UpdateAllocationStatsWithSize(cid, instance_size, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// instance: new object start as a tagged pointer.
@@ -3747,7 +3800,7 @@
}
-void Assembler::LoadClassById(Register result, Register class_id, Register pp) {
+void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
LoadIsolate(result);
const intptr_t offset =
@@ -3757,9 +3810,9 @@
}
-void Assembler::LoadClass(Register result, Register object, Register pp) {
+void Assembler::LoadClass(Register result, Register object) {
LoadClassId(TMP, object);
- LoadClassById(result, TMP, pp);
+ LoadClassById(result, TMP);
}
@@ -3794,7 +3847,7 @@
// Load up a null object. We only need it so we can use LoadClassId on it in
// the case that object is a Smi.
- LoadObject(result, Object::null_object(), PP);
+ LoadObject(result, Object::null_object());
// Check if the object is a Smi.
testq(object, Immediate(kSmiTagMask));
// If the object *is* a Smi, use the null object instead.
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index b7db5a5..edc7bc2 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -19,6 +19,7 @@
// Forward declarations.
class RuntimeEntry;
+class StubEntry;
class Immediate : public ValueObject {
public:
@@ -370,7 +371,7 @@
void pushq(Register reg);
void pushq(const Address& address);
void pushq(const Immediate& imm);
- void PushImmediate(const Immediate& imm, Register pp);
+ void PushImmediate(const Immediate& imm);
void popq(Register reg);
void popq(const Address& address);
@@ -527,9 +528,8 @@
void cmpq(Register reg0, Register reg1);
void cmpq(Register reg, const Address& address);
- void CompareImmediate(Register reg, const Immediate& imm, Register pp);
- void CompareImmediate(const Address& address, const Immediate& imm,
- Register pp);
+ void CompareImmediate(Register reg, const Immediate& imm);
+ void CompareImmediate(const Address& address, const Immediate& imm);
void testl(Register reg1, Register reg2);
void testl(Register reg, const Immediate& imm);
@@ -537,7 +537,7 @@
void testq(Register reg1, Register reg2);
void testq(Register reg, const Immediate& imm);
- void TestImmediate(Register dst, const Immediate& imm, Register pp);
+ void TestImmediate(Register dst, const Immediate& imm);
void andl(Register dst, Register src);
void andl(Register dst, const Immediate& imm);
@@ -551,18 +551,18 @@
void andq(Register dst, Register src);
void andq(Register dst, const Address& address);
void andq(Register dst, const Immediate& imm);
- void AndImmediate(Register dst, const Immediate& imm, Register pp);
+ void AndImmediate(Register dst, const Immediate& imm);
void orq(Register dst, Register src);
void orq(Register dst, const Address& address);
void orq(Register dst, const Immediate& imm);
- void OrImmediate(Register dst, const Immediate& imm, Register pp);
+ void OrImmediate(Register dst, const Immediate& imm);
void xorq(Register dst, Register src);
void xorq(Register dst, const Address& address);
void xorq(const Address& dst, Register src);
void xorq(Register dst, const Immediate& imm);
- void XorImmediate(Register dst, const Immediate& imm, Register pp);
+ void XorImmediate(Register dst, const Immediate& imm);
void addl(Register dst, Register src);
void addl(Register dst, const Immediate& imm);
@@ -597,7 +597,7 @@
void imulq(Register dst, Register src);
void imulq(Register dst, const Address& address);
void imulq(Register dst, const Immediate& imm);
- void MulImmediate(Register reg, const Immediate& imm, Register pp);
+ void MulImmediate(Register reg, const Immediate& imm);
void mulq(Register reg);
void subl(Register dst, Register src);
@@ -693,6 +693,7 @@
// Note: verified_mem mode forces far jumps.
void jmp(Label* label, bool near = kFarJump);
void jmp(const ExternalLabel* label);
+ void jmp(const StubEntry& stub_entry);
void lock();
void cmpxchgl(const Address& address, Register reg);
@@ -739,44 +740,48 @@
void MoveRegister(Register to, Register from);
void PopRegister(Register r);
- // Macros accepting a pp Register argument may attempt to load values from
- // the object pool when possible. Unless you are sure that the untagged object
- // pool pointer is in another register, or that it is not available at all,
- // PP should be passed for pp.
+ // Macros for adding/subtracting an immediate value that may be loaded from
+ // the constant pool.
// TODO(koda): Assert that these are not used for heap objects.
- void AddImmediate(Register reg, const Immediate& imm, Register pp);
- void AddImmediate(const Address& address, const Immediate& imm, Register pp);
- void SubImmediate(Register reg, const Immediate& imm, Register pp);
- void SubImmediate(const Address& address, const Immediate& imm, Register pp);
+ void AddImmediate(Register reg, const Immediate& imm);
+ void AddImmediate(const Address& address, const Immediate& imm);
+ void SubImmediate(Register reg, const Immediate& imm);
+ void SubImmediate(const Address& address, const Immediate& imm);
void Drop(intptr_t stack_elements, Register tmp = TMP);
- bool allow_constant_pool() const {
- return allow_constant_pool_;
+ bool constant_pool_allowed() const {
+ return constant_pool_allowed_;
}
- void set_allow_constant_pool(bool b) {
- allow_constant_pool_ = b;
+ void set_constant_pool_allowed(bool b) {
+ constant_pool_allowed_ = b;
}
- bool CanLoadImmediateFromPool(const Immediate& imm, Register pp);
- void LoadImmediate(Register reg, const Immediate& imm, Register pp);
+ void LoadImmediate(Register reg, const Immediate& imm);
void LoadIsolate(Register dst);
- void LoadObject(Register dst, const Object& obj, Register pp);
- void LoadUniqueObject(Register dst, const Object& obj, Register pp);
+ void LoadObject(Register dst, const Object& obj);
+ void LoadUniqueObject(Register dst, const Object& obj);
void LoadExternalLabel(Register dst,
const ExternalLabel* label,
- Patchability patchable,
- Register pp);
+ Patchability patchable);
+ void LoadFunctionFromCalleePool(Register dst,
+ const Function& function,
+ Register new_pp);
void JmpPatchable(const ExternalLabel* label, Register pp);
+ void JmpPatchable(const StubEntry& stub_entry, Register pp);
void Jmp(const ExternalLabel* label, Register pp);
+ void Jmp(const StubEntry& stub_entry, Register pp);
void J(Condition condition, const ExternalLabel* label, Register pp);
+ void J(Condition condition, const StubEntry& stub_entry, Register pp);
void CallPatchable(const ExternalLabel* label);
- void Call(const ExternalLabel* label, Register pp);
+ void CallPatchable(const StubEntry& stub_entry);
+ void Call(const ExternalLabel* label);
+ void Call(const StubEntry& stub_entry);
// Unaware of write barrier (use StoreInto* methods for storing to objects).
// TODO(koda): Add StackAddress/HeapAddress types to prevent misuse.
- void StoreObject(const Address& dst, const Object& obj, Register pp);
- void PushObject(const Object& object, Register pp);
- void CompareObject(Register reg, const Object& object, Register pp);
+ void StoreObject(const Address& dst, const Object& obj);
+ void PushObject(const Object& object);
+ void CompareObject(Register reg, const Object& object);
// When storing into a heap object field, knowledge of the previous content
// is expressed through these constants.
@@ -804,13 +809,11 @@
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
const Object& value,
- Register pp,
FieldContent old_content = kHeapObjectOrSmi);
void InitializeFieldNoBarrier(Register object,
const Address& dest,
- const Object& value,
- Register pp) {
- return StoreIntoObjectNoBarrier(object, dest, value, pp, kEmptyOrSmiOrNull);
+ const Object& value) {
+ return StoreIntoObjectNoBarrier(object, dest, value, kEmptyOrSmiOrNull);
}
// Stores a Smi value into a heap object field that always contains a Smi.
@@ -854,9 +857,9 @@
*/
void LoadClassId(Register result, Register object);
- void LoadClassById(Register result, Register class_id, Register pp);
+ void LoadClassById(Register result, Register class_id);
- void LoadClass(Register result, Register object, Register pp);
+ void LoadClass(Register result, Register object);
void CompareClassId(Register object, intptr_t class_id);
@@ -923,7 +926,7 @@
buffer_.FinalizeInstructions(region);
}
- void LoadPoolPointer(Register pp);
+ void LoadPoolPointer(Register pp = PP);
// Set up a Dart frame on entry with a frame pointer and PC information to
// enable easy access to the RawInstruction object of code corresponding
@@ -944,7 +947,6 @@
// ...
// pushq r15
// .....
- void EnterDartFrame(intptr_t frame_size);
void EnterDartFrameWithInfo(intptr_t frame_size,
Register new_pp, Register pc_marker_override);
void LeaveDartFrame();
@@ -1001,26 +1003,26 @@
// which will allocate in the runtime where tracing occurs.
void MaybeTraceAllocation(intptr_t cid,
Label* trace,
- bool near_jump);
+ bool near_jump,
+ bool inline_isolate = true);
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
// Only the tags field of the object is initialized.
- // Loads large immediates from the object pool with pool pointer in PP if it
- // is not kNoRegister
void TryAllocate(const Class& cls,
Label* failure,
bool near_jump,
Register instance_reg,
- Register pp);
+ Register temp);
void TryAllocateArray(intptr_t cid,
intptr_t instance_size,
Label* failure,
bool near_jump,
Register instance,
- Register end_address);
+ Register end_address,
+ Register temp);
// Debugging and bringup support.
void Stop(const char* message, bool fixed_length_encoding = false);
@@ -1073,15 +1075,12 @@
};
GrowableArray<CodeComment*> comments_;
- bool allow_constant_pool_;
+ bool constant_pool_allowed_;
intptr_t FindImmediate(int64_t imm);
bool CanLoadFromObjectPool(const Object& object) const;
- void LoadObjectHelper(Register dst,
- const Object& obj,
- Register pp,
- bool is_unique);
- void LoadWordFromPoolOffset(Register dst, Register pp, int32_t offset);
+ void LoadObjectHelper(Register dst, const Object& obj, bool is_unique);
+ void LoadWordFromPoolOffset(Register dst, int32_t offset);
inline void EmitUint8(uint8_t value);
inline void EmitInt32(int32_t value);
@@ -1132,7 +1131,7 @@
Register value,
FieldContent old_content);
// Unaware of write barrier (use StoreInto* methods for storing to objects).
- void MoveImmediate(const Address& dst, const Immediate& imm, Register pp);
+ void MoveImmediate(const Address& dst, const Immediate& imm);
void ComputeCounterAddressesForCid(intptr_t cid,
Heap::Space space,
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index a10b52e..cd99603 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -2026,7 +2026,7 @@
double b;
} constant0 = { 1.0, 2.0 };
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ negatepd(XMM10);
@@ -2049,7 +2049,7 @@
double b;
} constant0 = { -1.0, 2.0 };
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ abspd(XMM10);
@@ -2496,7 +2496,7 @@
ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ movl(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, RAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
@@ -2516,7 +2516,7 @@
ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ movl(RAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
__ movd(XMM0, RAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
@@ -2536,7 +2536,7 @@
ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ zerowps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0.
@@ -2658,8 +2658,8 @@
} constant1 =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadImmediate(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)), PP);
+ __ LoadPoolPointer();
+ __ LoadImmediate(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM9, Address(RAX, 0));
__ notps(XMM9);
__ movaps(XMM0, XMM9);
@@ -3067,26 +3067,26 @@
Label fail;
__ EnterFrame(0);
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadObject(RAX, obj, PP);
- __ CompareObject(RAX, obj, PP);
+ __ LoadPoolPointer();
+ __ LoadObject(RAX, obj);
+ __ CompareObject(RAX, obj);
__ j(NOT_EQUAL, &fail);
- __ LoadObject(RCX, obj, PP);
- __ CompareObject(RCX, obj, PP);
+ __ LoadObject(RCX, obj);
+ __ CompareObject(RCX, obj);
__ j(NOT_EQUAL, &fail);
const Smi& smi = Smi::ZoneHandle(Smi::New(15));
- __ LoadObject(RCX, smi, PP);
- __ CompareObject(RCX, smi, PP);
+ __ LoadObject(RCX, smi);
+ __ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ pushq(RAX);
- __ StoreObject(Address(RSP, 0), obj, PP);
+ __ StoreObject(Address(RSP, 0), obj);
__ popq(RCX);
- __ CompareObject(RCX, obj, PP);
+ __ CompareObject(RCX, obj);
__ j(NOT_EQUAL, &fail);
__ pushq(RAX);
- __ StoreObject(Address(RSP, 0), smi, PP);
+ __ StoreObject(Address(RSP, 0), smi);
__ popq(RCX);
- __ CompareObject(RCX, smi, PP);
+ __ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ movl(RAX, Immediate(1)); // OK
__ popq(PP); // Restore caller's pool pointer.
@@ -3307,7 +3307,7 @@
// Called from assembler_test.cc.
ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ pushq(THR);
__ movq(THR, CallingConventions::kArg4Reg);
__ pushq(CTX);
@@ -3433,7 +3433,7 @@
ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
__ DoubleAbs(XMM0);
__ popq(PP); // Restore caller's pool pointer.
__ ret();
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index ef224e2..26618b5 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -229,8 +229,6 @@
return NULL;
case Token::kEQ:
case Token::kNE:
- case Token::kEQ_STRICT:
- case Token::kNE_STRICT:
// The comparison is a compile time const if both operands are either a
// number, string, or boolean value (but not necessarily the same type).
if ((left_val->IsNumber() ||
@@ -244,6 +242,11 @@
return &Bool::False();
}
return NULL;
+ case Token::kEQ_STRICT:
+ case Token::kNE_STRICT:
+ // identical(a, b) is a compile time const if both operands are
+ // compile time constants, regardless of their type.
+ return &Bool::True();
default:
return NULL;
}
diff --git a/runtime/vm/base_isolate.h b/runtime/vm/base_isolate.h
index fc6de2b..33c5f4d3 100644
--- a/runtime/vm/base_isolate.h
+++ b/runtime/vm/base_isolate.h
@@ -26,28 +26,6 @@
void AssertCurrentThreadIsMutator() const {}
#endif // DEBUG
- int32_t no_safepoint_scope_depth() const {
-#if defined(DEBUG)
- return no_safepoint_scope_depth_;
-#else
- return 0;
-#endif
- }
-
- void IncrementNoSafepointScopeDepth() {
-#if defined(DEBUG)
- ASSERT(no_safepoint_scope_depth_ < INT_MAX);
- no_safepoint_scope_depth_ += 1;
-#endif
- }
-
- void DecrementNoSafepointScopeDepth() {
-#if defined(DEBUG)
- ASSERT(no_safepoint_scope_depth_ > 0);
- no_safepoint_scope_depth_ -= 1;
-#endif
- }
-
int32_t no_callback_scope_depth() const {
return no_callback_scope_depth_;
}
@@ -69,20 +47,14 @@
protected:
BaseIsolate()
: mutator_thread_(NULL),
-#if defined(DEBUG)
- no_safepoint_scope_depth_(0),
-#endif
- no_callback_scope_depth_(0)
- {}
+ no_callback_scope_depth_(0) {
+ }
~BaseIsolate() {
// Do not delete stack resources: top_resource_ and current_zone_.
}
Thread* mutator_thread_;
-#if defined(DEBUG)
- int32_t no_safepoint_scope_depth_;
-#endif
int32_t no_callback_scope_depth_;
private:
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index a6d6c18..7f51ac4 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -258,6 +258,68 @@
}
+// Emulates DartUtils::PrepareForScriptLoading.
+static Dart_Handle PreparePackageRoot(const char* package_root,
+ Dart_Handle builtin_lib) {
+ // First ensure all required libraries are available.
+ Dart_Handle url = NewString(bin::DartUtils::kCoreLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle core_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(core_lib);
+ url = NewString(bin::DartUtils::kAsyncLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle async_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(async_lib);
+ url = NewString(bin::DartUtils::kIsolateLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle isolate_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(isolate_lib);
+ url = NewString(bin::DartUtils::kInternalLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle internal_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(internal_lib);
+ Dart_Handle io_lib =
+ bin::Builtin::LoadAndCheckLibrary(bin::Builtin::kIOLibrary);
+ DART_CHECK_VALID(io_lib);
+
+ // We need to ensure that all the scripts loaded so far are finalized
+ // as we are about to invoke some Dart code below to setup closures.
+ Dart_Handle result = Dart_FinalizeLoading(false);
+ DART_CHECK_VALID(result);
+
+ // Necessary parts from PrepareBuiltinLibrary.
+ // Setup the internal library's 'internalPrint' function.
+ result = Dart_Invoke(builtin_lib, NewString("_getPrintClosure"), 0, NULL);
+ DART_CHECK_VALID(result);
+ result = Dart_SetField(internal_lib, NewString("_printClosure"), result);
+ DART_CHECK_VALID(result);
+#if defined(TARGET_OS_WINDOWS)
+ result = Dart_SetField(builtin_lib, NewString("_isWindows"), Dart_True());
+ DART_CHECK_VALID(result);
+#endif // defined(TARGET_OS_WINDOWS)
+ // Set current working directory.
+ result = bin::DartUtils::SetWorkingDirectory(builtin_lib);
+ DART_CHECK_VALID(result);
+ // Set the package root for builtin.dart.
+ result = NewString(package_root);
+ DART_CHECK_VALID(result);
+ const int kNumArgs = 1;
+ Dart_Handle dart_args[kNumArgs];
+ dart_args[0] = result;
+ result = Dart_Invoke(builtin_lib,
+ NewString("_setPackageRoot"),
+ kNumArgs,
+ dart_args);
+ DART_CHECK_VALID(result);
+
+ bin::DartUtils::PrepareAsyncLibrary(async_lib, isolate_lib);
+ bin::DartUtils::PrepareCoreLibrary(core_lib, builtin_lib, false);
+ bin::DartUtils::PrepareIsolateLibrary(isolate_lib);
+ bin::DartUtils::PrepareIOLibrary(io_lib);
+ return Dart_True();
+}
+
+
static Dart_NativeFunction NativeResolver(Dart_Handle name,
int arg_count,
bool* auto_setup_scope) {
@@ -280,7 +342,8 @@
const char* path_separator = File::PathSeparator();
OS::SNPrint(buffer, 2048, packages_path,
executable_path, path_separator, path_separator);
- bin::DartUtils::PrepareForScriptLoading(buffer, false, false, builtin_lib);
+ Dart_Handle result = PreparePackageRoot(buffer, builtin_lib);
+ DART_CHECK_VALID(result);
}
BENCHMARK(Dart2JSCompileAll) {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index cab3102..0358a00 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -70,6 +70,7 @@
V(Bigint_allocate, 4) \
V(Developer_debugger, 2) \
V(Developer_inspect, 1) \
+ V(Developer_log, 8) \
V(Double_getIsNegative, 1) \
V(Double_getIsInfinite, 1) \
V(Double_getIsNaN, 1) \
diff --git a/runtime/vm/cha.h b/runtime/vm/cha.h
index b4007b2..fac6577 100644
--- a/runtime/vm/cha.h
+++ b/runtime/vm/cha.h
@@ -19,7 +19,7 @@
class CHA : public StackResource {
public:
explicit CHA(Thread* thread)
- : StackResource(thread->isolate()),
+ : StackResource(thread),
thread_(thread),
leaf_classes_(thread->zone(), 1),
previous_(thread->cha()) {
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index c4dbfe8..28b7f75 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -450,10 +450,8 @@
}
-ClassHeapStats** ClassTable::StateAddressFor(intptr_t cid,
- intptr_t* state_offset) {
- *state_offset = ClassOffsetFor(cid)+ ClassHeapStats::state_offset();
- return TableAddressFor(cid);
+intptr_t ClassTable::StateOffsetFor(intptr_t cid) {
+ return ClassOffsetFor(cid)+ ClassHeapStats::state_offset();
}
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 93fb514..aebf15c 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -155,7 +155,7 @@
return table_[index];
}
- intptr_t IsValidIndex(intptr_t index) const {
+ bool IsValidIndex(intptr_t index) const {
return (index > 0) && (index < top_);
}
@@ -205,8 +205,7 @@
static intptr_t CounterOffsetFor(intptr_t cid, bool is_new_space);
// Used by the generated code.
- ClassHeapStats** StateAddressFor(intptr_t cid,
- intptr_t* state_offset);
+ static intptr_t StateOffsetFor(intptr_t cid);
// Used by the generated code.
static intptr_t SizeOffsetFor(intptr_t cid, bool is_new_space);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index dd977b2..5df3636 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -23,6 +23,7 @@
#include "vm/runtime_entry.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
+#include "vm/thread_registry.h"
#include "vm/verifier.h"
namespace dart {
@@ -1053,23 +1054,72 @@
// a zigzagged lookup to see if this call failed because of an arity mismatch,
// need for conversion, or there really is no such method.
+#define NO_SUCH_METHOD() \
+ const Object& result = Object::Handle( \
+ DartEntry::InvokeNoSuchMethod(receiver, \
+ target_name, \
+ orig_arguments, \
+ orig_arguments_desc)); \
+ CheckResultError(result); \
+ arguments.SetReturn(result); \
+
+#define CLOSURIZE(some_function) \
+ const Function& closure_function = \
+ Function::Handle(some_function.ImplicitClosureFunction()); \
+ const Object& result = \
+ Object::Handle(closure_function.ImplicitInstanceClosure(receiver)); \
+ arguments.SetReturn(result); \
+
const bool is_getter = Field::IsGetterName(target_name);
if (is_getter) {
- // o.foo failed, closurize o.foo() if it exists
- const String& field_name =
- String::Handle(Field::NameFromGetter(target_name));
+ // o.foo (o.get:foo) failed, closurize o.foo() if it exists. Or,
+ // o#foo (o.get:#foo) failed, closurizee o.foo or o.foo(), whichever is
+ // encountered first on the inheritance chain. Or,
+ // o#foo= (o.get:#set:foo) failed, closurize o.foo= if it exists.
+ String& field_name =
+ String::Handle(Field::NameFromGetter(target_name));
+
+ const bool is_extractor = field_name.CharAt(0) == '#';
+ if (is_extractor) {
+ field_name = String::SubString(field_name, 1);
+ ASSERT(!Field::IsGetterName(field_name));
+ field_name = Symbols::New(field_name);
+
+ if (!Field::IsSetterName(field_name)) {
+ const String& getter_name =
+ String::Handle(Field::GetterName(field_name));
+
+ // Zigzagged lookup: closure either a regular method or a getter.
+ while (!cls.IsNull()) {
+ function ^= cls.LookupDynamicFunction(field_name);
+ if (!function.IsNull()) {
+ CLOSURIZE(function);
+ return;
+ }
+ function ^= cls.LookupDynamicFunction(getter_name);
+ if (!function.IsNull()) {
+ CLOSURIZE(function);
+ return;
+ }
+ cls = cls.SuperClass();
+ }
+ NO_SUCH_METHOD();
+ return;
+ } else {
+ // Fall through for non-ziggaged lookup for o#foo=.
+ }
+ }
+
while (!cls.IsNull()) {
function ^= cls.LookupDynamicFunction(field_name);
if (!function.IsNull()) {
- const Function& closure_function =
- Function::Handle(function.ImplicitClosureFunction());
- const Object& result =
- Object::Handle(closure_function.ImplicitInstanceClosure(receiver));
- arguments.SetReturn(result);
+ CLOSURIZE(function);
return;
}
cls = cls.SuperClass();
}
+
+ // Fall through for noSuchMethod
} else {
// o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong
// number of arguments, or try (o.foo).call(...)
@@ -1116,14 +1166,10 @@
}
}
- // Handle noSuchMethod invocation.
- const Object& result = Object::Handle(
- DartEntry::InvokeNoSuchMethod(receiver,
- target_name,
- orig_arguments,
- orig_arguments_desc));
- CheckResultError(result);
- arguments.SetReturn(result);
+ NO_SUCH_METHOD();
+
+#undef NO_SUCH_METHOD
+#undef CLOSURIZE
}
@@ -1299,11 +1345,14 @@
}
uword interrupt_bits = isolate->GetAndClearInterrupts();
- if ((interrupt_bits & Isolate::kStoreBufferInterrupt) != 0) {
- if (FLAG_verbose_gc) {
- OS::PrintErr("Scavenge scheduled by store buffer overflow.\n");
+ if ((interrupt_bits & Isolate::kVMInterrupt) != 0) {
+ isolate->thread_registry()->CheckSafepoint();
+ if (isolate->store_buffer()->Overflowed()) {
+ if (FLAG_verbose_gc) {
+ OS::PrintErr("Scavenge scheduled by store buffer overflow.\n");
+ }
+ isolate->heap()->CollectGarbage(Heap::kNew);
}
- isolate->heap()->CollectGarbage(Heap::kNew);
}
if ((interrupt_bits & Isolate::kMessageInterrupt) != 0) {
bool ok = isolate->message_handler()->HandleOOBMessages();
@@ -1508,7 +1557,7 @@
alloc_class ^= stub.owner();
Code& alloc_stub = Code::Handle(isolate, alloc_class.allocation_stub());
if (alloc_stub.IsNull()) {
- alloc_stub = isolate->stub_code()->GetAllocationStubForClass(alloc_class);
+ alloc_stub = StubCode::GetAllocationStubForClass(alloc_class);
ASSERT(!CodePatcher::IsEntryPatched(alloc_stub));
}
const Instructions& instrs =
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index e02fee9..bb7008a 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -39,10 +39,11 @@
15,
1));
- __ LoadObject(R5, ic_data, PP);
- StubCode* stub_code = Isolate::Current()->stub_code();
- ExternalLabel target_label(stub_code->OneArgCheckInlineCacheEntryPoint());
- __ BranchLinkPatchable(&target_label);
+ // Code accessing pp is generated, but not executed. Uninitialized pp is OK.
+ __ set_constant_pool_allowed(true);
+
+ __ LoadObject(R5, ic_data);
+ __ BranchLinkPatchable(*StubCode::OneArgCheckInlineCache_entry());
__ ret();
}
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index 1603e7c..525b3db 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -39,10 +39,11 @@
15,
1));
+ // Code accessing pp is generated, but not executed. Uninitialized pp is OK.
+ __ set_constant_pool_allowed(true);
+
__ LoadObject(R5, ic_data);
- StubCode* stub_code = Isolate::Current()->stub_code();
- ExternalLabel target_label(stub_code->OneArgCheckInlineCacheEntryPoint());
- __ BranchLinkPatchable(&target_label);
+ __ BranchLinkPatchable(*StubCode::OneArgCheckInlineCache_entry());
__ Ret();
}
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index c0321e8..a9c62f4 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -40,9 +40,7 @@
1));
__ LoadObject(ECX, ic_data);
- StubCode* stub_code = Isolate::Current()->stub_code();
- ExternalLabel target_label(stub_code->OneArgCheckInlineCacheEntryPoint());
- __ call(&target_label);
+ __ Call(*StubCode::OneArgCheckInlineCache_entry());
__ ret();
}
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index 3c73a3c..78e698b 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -40,9 +40,7 @@
1));
__ LoadObject(S5, ic_data);
- StubCode* stub_code = Isolate::Current()->stub_code();
- ExternalLabel target_label(stub_code->OneArgCheckInlineCacheEntryPoint());
- __ BranchLinkPatchable(&target_label);
+ __ BranchLinkPatchable(*StubCode::OneArgCheckInlineCache_entry());
__ Ret();
}
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index f6ad37f..ca98231 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -39,10 +39,11 @@
15,
1));
- __ LoadObject(RBX, ic_data, PP);
- StubCode* stub_code = Isolate::Current()->stub_code();
- ExternalLabel target_label(stub_code->OneArgCheckInlineCacheEntryPoint());
- __ CallPatchable(&target_label);
+ // Code accessing pp is generated, but not executed. Uninitialized pp is OK.
+ __ set_constant_pool_allowed(true);
+
+ __ LoadObject(RBX, ic_data);
+ __ CallPatchable(*StubCode::OneArgCheckInlineCache_entry());
__ ret();
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 491b571..1eb55f3 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -744,6 +744,12 @@
inlined_id_array.Length() * sizeof(uword));
code.SetInlinedIdToFunction(inlined_id_array);
+ const Array& caller_inlining_id_map_array =
+ Array::Handle(isolate, graph_compiler.CallerInliningIdMap());
+ INC_STAT(isolate, total_code_size,
+ caller_inlining_id_map_array.Length() * sizeof(uword));
+ code.SetInlinedCallerIdMap(caller_inlining_id_map_array);
+
graph_compiler.FinalizePcDescriptors(code);
code.set_deopt_info_array(deopt_info_array);
@@ -971,6 +977,27 @@
}
+#if defined(DEBUG)
+// Verifies that the inliner is always in the list of inlined functions.
+// If this fails run with --trace-inlining-intervals to get more information.
+static void CheckInliningIntervals(const Function& function) {
+ const Code& code = Code::Handle(function.CurrentCode());
+ const Array& intervals = Array::Handle(code.GetInlinedIntervals());
+ if (intervals.IsNull() || (intervals.Length() == 0)) return;
+ Smi& start = Smi::Handle();
+ GrowableArray<Function*> inlined_functions;
+ for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) {
+ start ^= intervals.At(i + Code::kInlIntStart);
+ ASSERT(!start.IsNull());
+ if (start.IsNull()) continue;
+ code.GetInlinedFunctionsAt(start.Value(), &inlined_functions);
+ ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() ==
+ function.raw());
+ }
+}
+#endif
+
+
static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
const Function& function,
bool optimized,
@@ -1059,6 +1086,9 @@
DisassembleCode(function, true);
ISL_Print("*** END CODE\n");
}
+#if defined(DEBUG)
+ CheckInliningIntervals(function);
+#endif
return Error::null();
} else {
Thread* const thread = Thread::Current();
@@ -1081,6 +1111,13 @@
VMTagScope tagScope(isolate, VMTag::kCompileUnoptimizedTagId);
TIMELINE_FUNCTION_COMPILATION_DURATION(isolate, "Function", function);
+ if (!isolate->compilation_allowed()) {
+ FATAL3("Precompilation missed function %s (%" Pd ", %s)\n",
+ function.ToLibNamePrefixedQualifiedCString(),
+ function.token_pos(),
+ Function::KindToCString(function.kind()));
+ }
+
CompilationPipeline* pipeline =
CompilationPipeline::New(thread->zone(), function);
@@ -1241,6 +1278,33 @@
}
+void Compiler::CompileStaticInitializer(const Field& field) {
+ ASSERT(field.is_static());
+ if (field.initializer() != Function::null()) {
+ // TODO(rmacnak): Investigate why this happens for _enum_names.
+ OS::Print("Warning: Ignoring repeated request for initializer for %s\n",
+ field.ToCString());
+ return;
+ }
+ ASSERT(field.initializer() == Function::null());
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+
+ ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
+
+ parsed_function->AllocateVariables();
+ // Non-optimized code generator.
+ DartCompilationPipeline pipeline;
+ CompileParsedFunctionHelper(&pipeline,
+ parsed_function,
+ false, // optimized
+ Isolate::kNoDeoptId);
+
+ const Function& initializer = parsed_function->function();
+ field.set_initializer(initializer);
+}
+
+
RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
ASSERT(field.is_static());
// The VM sets the field's value to transiton_sentinel prior to
@@ -1248,23 +1312,31 @@
ASSERT(field.value() == Object::transition_sentinel().raw());
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- Isolate* const isolate = Isolate::Current();
- StackZone zone(isolate);
- ParsedFunction* parsed_function =
- Parser::ParseStaticFieldInitializer(field);
+ Function& initializer = Function::Handle(field.initializer());
- parsed_function->AllocateVariables();
- // Non-optimized code generator.
- DartCompilationPipeline pipeline;
- CompileParsedFunctionHelper(&pipeline,
- parsed_function,
- false,
- Isolate::kNoDeoptId);
- // Eagerly create local var descriptors.
- CreateLocalVarDescriptors(*parsed_function);
+ // Under precompilation, the initializer may have already been compiled, in
+ // which case use it. Under lazy compilation or early in precompilation, the
+ // initializer has not yet been created, so create it now, but don't bother
+ // remembering it because it won't be used again.
+ if (initializer.IsNull()) {
+ Isolate* const isolate = Isolate::Current();
+ StackZone zone(isolate);
+ ParsedFunction* parsed_function =
+ Parser::ParseStaticFieldInitializer(field);
+ parsed_function->AllocateVariables();
+ // Non-optimized code generator.
+ DartCompilationPipeline pipeline;
+ CompileParsedFunctionHelper(&pipeline,
+ parsed_function,
+ false, // optimized
+ Isolate::kNoDeoptId);
+ // Eagerly create local var descriptors.
+ CreateLocalVarDescriptors(*parsed_function);
+
+ initializer = parsed_function->function().raw();
+ }
// Invoke the function to evaluate the expression.
- const Function& initializer = parsed_function->function();
const Object& result = PassiveObject::Handle(
DartEntry::InvokeFunction(initializer, Object::empty_array()));
return result.raw();
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index e8052c7..746d5d8 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -72,6 +72,7 @@
// The return value is either a RawInstance on success or a RawError
// on compilation failure.
static RawObject* EvaluateStaticInitializer(const Field& field);
+ static void CompileStaticInitializer(const Field& field);
// Generates local var descriptors and sets it in 'code'. Do not call if the
// local var descriptor already exists.
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index 18a47ac..aa5b892 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -90,9 +90,8 @@
EXPECT(!cls.IsNull());
Isolate* isolate = Isolate::Current();
- StubCode* stub_code = isolate->stub_code();
const Code& stub = Code::Handle(isolate,
- stub_code->GetAllocationStubForClass(cls));
+ StubCode::GetAllocationStubForClass(cls));
Class& owner = Class::Handle();
owner ^= stub.owner();
owner.DisableAllocationStub();
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 35bab84..29818e1 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -735,7 +735,7 @@
void ConstantPropagator::VisitInstanceOf(InstanceOfInstr* instr) {
- const Definition* def = instr->value()->definition();
+ Definition* def = instr->value()->definition();
const Object& value = def->constant_value();
if (IsNonConstant(value)) {
const AbstractType& checked_type = instr->type();
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index f1834b8..f84cf68 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -111,7 +111,6 @@
const Register TMP2 = R17;
const Register CTX = R28; // Location of current context at method entry.
const Register PP = R27; // Caches object pool pointer in generated code.
-const Register kNoPP = kNoRegister;
const Register FPREG = FP; // Frame pointer register.
const Register SPREG = R18; // Stack pointer register.
const Register LRREG = LR; // Link register.
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 7bb4fe3..60439a2 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -33,18 +33,8 @@
namespace dart {
-DEFINE_FLAG(int, new_gen_semi_max_size, (kWordSize <= 4) ? 16 : 32,
- "Max size of new gen semi space in MB");
-DEFINE_FLAG(int, old_gen_heap_size, 0,
- "Max size of old gen heap size in MB, or 0 for unlimited,"
- "e.g: --old_gen_heap_size=1024 allows up to 1024MB old gen heap");
-DEFINE_FLAG(int, external_max_size, (kWordSize <= 4) ? 512 : 1024,
- "Max total size of external allocations in MB, or 0 for unlimited,"
- "e.g: --external_max_size=1024 allows up to 1024MB of externals");
-
DEFINE_FLAG(bool, keep_code, false,
"Keep deoptimized code for profiling.");
-
DECLARE_FLAG(bool, print_class_table);
DECLARE_FLAG(bool, trace_isolates);
@@ -129,10 +119,6 @@
StackZone zone(vm_isolate_);
HandleScope handle_scope(vm_isolate_);
- Heap::Init(vm_isolate_,
- 0, // New gen size 0; VM isolate should only allocate in old.
- FLAG_old_gen_heap_size * MBInWords,
- FLAG_external_max_size * MBInWords);
Object::InitNull(vm_isolate_);
ObjectStore::Init(vm_isolate_);
TargetCPUFeatures::InitOnce();
@@ -250,10 +236,6 @@
ASSERT(isolate != NULL);
StackZone zone(isolate);
HandleScope handle_scope(isolate);
- Heap::Init(isolate,
- FLAG_new_gen_semi_max_size * MBInWords,
- FLAG_old_gen_heap_size * MBInWords,
- FLAG_external_max_size * MBInWords);
ObjectStore::Init(isolate);
// Setup for profiling.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index b701c0e..038bfc8 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1364,28 +1364,31 @@
}
Isolate* isolate = Dart::CreateIsolate(isolate_name, *flags);
free(isolate_name);
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
- // We enter an API scope here as InitializeIsolate could compile some
- // bootstrap library files which call out to a tag handler that may create
- // Api Handles when an error is encountered.
- Dart_EnterScope();
- const Error& error_obj =
- Error::Handle(isolate, Dart::InitializeIsolate(snapshot, callback_data));
- if (error_obj.IsNull()) {
-#if defined(DART_NO_SNAPSHOT)
- if (FLAG_check_function_fingerprints) {
- Library::CheckFunctionFingerprints();
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ // We enter an API scope here as InitializeIsolate could compile some
+ // bootstrap library files which call out to a tag handler that may create
+ // Api Handles when an error is encountered.
+ Dart_EnterScope();
+ const Error& error_obj =
+ Error::Handle(isolate,
+ Dart::InitializeIsolate(snapshot, callback_data));
+ if (error_obj.IsNull()) {
+ #if defined(DART_NO_SNAPSHOT)
+ if (FLAG_check_function_fingerprints) {
+ Library::CheckFunctionFingerprints();
+ }
+ #endif // defined(DART_NO_SNAPSHOT).
+ // We exit the API scope entered above.
+ Dart_ExitScope();
+ START_TIMER(isolate, time_total_runtime);
+ return Api::CastIsolate(isolate);
}
-#endif // defined(DART_NO_SNAPSHOT).
+ *error = strdup(error_obj.ToErrorCString());
// We exit the API scope entered above.
Dart_ExitScope();
- START_TIMER(isolate, time_total_runtime);
- return Api::CastIsolate(isolate);
}
- *error = strdup(error_obj.ToErrorCString());
- // We exit the API scope entered above.
- Dart_ExitScope();
Dart::ShutdownIsolate();
return reinterpret_cast<Dart_Isolate>(NULL);
}
@@ -1439,7 +1442,7 @@
CHECK_NO_ISOLATE(Isolate::Current());
// TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
- if (iso->mutator_thread() != NULL) {
+ if (iso->HasMutatorThread()) {
FATAL("Multiple mutators within one isolate is not supported.");
}
Thread::EnsureInit();
@@ -1773,19 +1776,20 @@
// --- Scopes ----
DART_EXPORT void Dart_EnterScope() {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
ApiLocalScope* new_scope = state->reusable_scope();
if (new_scope == NULL) {
new_scope = new ApiLocalScope(state->top_scope(),
- isolate->top_exit_frame_info());
+ thread->top_exit_frame_info());
ASSERT(new_scope != NULL);
} else {
- new_scope->Reinit(isolate,
+ new_scope->Reinit(thread,
state->top_scope(),
- isolate->top_exit_frame_info());
+ thread->top_exit_frame_info());
state->set_reusable_scope(NULL);
}
state->set_top_scope(new_scope); // New scope is now the top scope.
@@ -1793,14 +1797,15 @@
DART_EXPORT void Dart_ExitScope() {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
CHECK_ISOLATE_SCOPE(isolate);
ApiState* state = isolate->api_state();
ApiLocalScope* scope = state->top_scope();
ApiLocalScope* reusable_scope = state->reusable_scope();
state->set_top_scope(scope->previous()); // Reset top scope to previous.
if (reusable_scope == NULL) {
- scope->Reset(isolate); // Reset the old scope which we just exited.
+ scope->Reset(thread); // Reset the old scope which we just exited.
state->set_reusable_scope(scope);
} else {
ASSERT(reusable_scope != scope);
@@ -3587,7 +3592,8 @@
Dart_TypedData_Type* type,
void** data,
intptr_t* len) {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
DARTSCOPE(isolate);
intptr_t class_id = Api::ClassId(object);
if (!RawObject::IsExternalTypedDataClassId(class_id) &&
@@ -3625,7 +3631,7 @@
ASSERT(!obj.IsNull());
length = obj.Length();
size_in_bytes = length * TypedData::ElementSizeInBytes(class_id);
- isolate->IncrementNoSafepointScopeDepth();
+ thread->IncrementNoSafepointScopeDepth();
START_NO_CALLBACK_SCOPE(isolate);
data_tmp = obj.DataAddr(0);
} else {
@@ -3639,7 +3645,7 @@
val ^= TypedDataView::OffsetInBytes(view_obj);
intptr_t offset_in_bytes = val.Value();
const Instance& obj = Instance::Handle(TypedDataView::Data(view_obj));
- isolate->IncrementNoSafepointScopeDepth();
+ thread->IncrementNoSafepointScopeDepth();
START_NO_CALLBACK_SCOPE(isolate);
if (TypedData::IsTypedData(obj)) {
const TypedData& data_obj = TypedData::Cast(obj);
@@ -3677,7 +3683,8 @@
DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
DARTSCOPE(isolate);
intptr_t class_id = Api::ClassId(object);
if (!RawObject::IsExternalTypedDataClassId(class_id) &&
@@ -3686,7 +3693,7 @@
RETURN_TYPE_ERROR(isolate, object, 'TypedData');
}
if (!RawObject::IsExternalTypedDataClassId(class_id)) {
- isolate->DecrementNoSafepointScopeDepth();
+ thread->DecrementNoSafepointScopeDepth();
END_NO_CALLBACK_SCOPE(isolate);
}
if (FLAG_verify_acquired_data) {
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 2ee1c37..aa08099 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -481,6 +481,9 @@
object_id = NextAvailableObjectId();
}
+ intptr_t tags = ReadTags();
+ USE(tags);
+
// Reading of regular dart instances has limited support in order to
// read typed data views.
if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) {
@@ -502,10 +505,6 @@
AddBackRef(object_id, value, kIsNotDeserialized);
return value;
}
-
- intptr_t tags = ReadTags();
- USE(tags);
-
return ReadInternalVMObject(class_id, object_id);
}
@@ -682,6 +681,13 @@
AddBackRef(object_id, object, kIsDeserialized);
return object;
}
+ case kCapabilityCid: {
+ int64_t id = Read<int64_t>();
+ Dart_CObject* object = AllocateDartCObject(Dart_CObject_kCapability);
+ object->value.as_capability.id = id;
+ AddBackRef(object_id, object, kIsDeserialized);
+ return object;
+ }
#define READ_TYPED_DATA_HEADER(type) \
intptr_t len = ReadSmiValue(); \
@@ -1060,6 +1066,7 @@
WriteInlinedHeader(object);
// Write out the class information.
WriteIndexedObject(kArrayCid);
+ WriteTags(0);
// Write out the length information.
WriteSmi(array_length);
// Add object to forward list so that this object is serialized later.
@@ -1268,6 +1275,13 @@
WriteRawPointerValue(reinterpret_cast<intptr_t>(callback));
break;
}
+ case Dart_CObject_kCapability: {
+ WriteInlinedHeader(object);
+ WriteIndexedObject(kCapabilityCid);
+ WriteTags(0);
+ Write<uint64_t>(object->value.as_capability.id);
+ break;
+ }
default:
UNREACHABLE();
}
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index 4f293540..207aab4 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -35,11 +35,11 @@
public:
// Create an empty zone.
ApiZone() : zone_() {
- Isolate* isolate = Isolate::Current();
- Zone* current_zone = isolate != NULL ? isolate->current_zone() : NULL;
- zone_.Link(current_zone);
- if (isolate != NULL) {
- isolate->set_current_zone(&zone_);
+ Thread* thread = Thread::Current();
+ Zone* zone = thread != NULL ? thread->zone() : NULL;
+ zone_.Link(zone);
+ if (thread != NULL) {
+ thread->set_zone(&zone_);
}
#ifdef DEBUG
if (FLAG_trace_zones) {
@@ -52,15 +52,15 @@
// Delete all memory associated with the zone.
~ApiZone() {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
#if defined(DEBUG)
- if (isolate == NULL) {
+ if (thread == NULL) {
ASSERT(zone_.handles()->CountScopedHandles() == 0);
ASSERT(zone_.handles()->CountZoneHandles() == 0);
}
#endif
- if ((isolate != NULL) && (isolate->current_zone() == &zone_)) {
- isolate->set_current_zone(zone_.previous_);
+ if ((thread != NULL) && (thread->zone() == &zone_)) {
+ thread->set_zone(zone_.previous_);
}
#ifdef DEBUG
if (FLAG_trace_zones) {
@@ -101,18 +101,18 @@
Zone* GetZone() { return &zone_; }
- void Reinit(Isolate* isolate) {
- if (isolate == NULL) {
+ void Reinit(Thread* thread) {
+ if (thread == NULL) {
zone_.Link(NULL);
} else {
- zone_.Link(isolate->current_zone());
- isolate->set_current_zone(&zone_);
+ zone_.Link(thread->zone());
+ thread->set_zone(&zone_);
}
}
- void Reset(Isolate* isolate) {
- if ((isolate != NULL) && (isolate->current_zone() == &zone_)) {
- isolate->set_current_zone(zone_.previous_);
+ void Reset(Thread* thread) {
+ if ((thread != NULL) && (thread->zone() == &zone_)) {
+ thread->set_zone(zone_.previous_);
}
zone_.DeleteAll();
}
@@ -592,16 +592,16 @@
}
// Reinit the ApiLocalScope to new values.
- void Reinit(Isolate* isolate, ApiLocalScope* previous, uword stack_marker) {
+ void Reinit(Thread* thread, ApiLocalScope* previous, uword stack_marker) {
previous_ = previous;
stack_marker_ = stack_marker;
- zone_.Reinit(isolate);
+ zone_.Reinit(thread);
}
// Reset the ApiLocalScope so that it can be reused again.
- void Reset(Isolate* isolate) {
+ void Reset(Thread* thread) {
local_handles_.Reset();
- zone_.Reset(isolate);
+ zone_.Reset(thread);
previous_ = NULL;
stack_marker_ = 0;
}
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 817b7e9..211ce7f 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -93,7 +93,7 @@
}
// Now Call the invoke stub which will invoke the dart function.
invokestub entrypoint = reinterpret_cast<invokestub>(
- isolate->stub_code()->InvokeDartCodeEntryPoint());
+ StubCode::InvokeDartCode_entry()->EntryPoint());
const Code& code = Code::Handle(zone, function.CurrentCode());
ASSERT(!code.IsNull());
ASSERT(Isolate::Current()->no_callback_scope_depth() == 0);
diff --git a/runtime/vm/debugger_arm.cc b/runtime/vm/debugger_arm.cc
index e84ffa9..e0a366d 100644
--- a/runtime/vm/debugger_arm.cc
+++ b/runtime/vm/debugger_arm.cc
@@ -20,15 +20,14 @@
void CodeBreakpoint::PatchCode() {
ASSERT(!is_enabled_);
- StubCode* stub_code = Isolate::Current()->stub_code();
uword stub_target = 0;
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = stub_code->ICCallBreakpointEntryPoint();
+ stub_target = StubCode::ICCallBreakpoint_entry()->EntryPoint();
break;
case RawPcDescriptors::kRuntimeCall:
- stub_target = stub_code->RuntimeCallBreakpointEntryPoint();
+ stub_target = StubCode::RuntimeCallBreakpoint_entry()->EntryPoint();
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/debugger_arm64.cc b/runtime/vm/debugger_arm64.cc
index 0674495..8c59d24 100644
--- a/runtime/vm/debugger_arm64.cc
+++ b/runtime/vm/debugger_arm64.cc
@@ -20,15 +20,14 @@
void CodeBreakpoint::PatchCode() {
ASSERT(!is_enabled_);
- StubCode* stub_code = Isolate::Current()->stub_code();
uword stub_target = 0;
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = stub_code->ICCallBreakpointEntryPoint();
+ stub_target = StubCode::ICCallBreakpoint_entry()->EntryPoint();
break;
case RawPcDescriptors::kRuntimeCall: {
- stub_target = stub_code->RuntimeCallBreakpointEntryPoint();
+ stub_target = StubCode::RuntimeCallBreakpoint_entry()->EntryPoint();
break;
}
default:
diff --git a/runtime/vm/debugger_ia32.cc b/runtime/vm/debugger_ia32.cc
index 6b9ae72..408c838 100644
--- a/runtime/vm/debugger_ia32.cc
+++ b/runtime/vm/debugger_ia32.cc
@@ -26,7 +26,6 @@
ASSERT(!is_enabled_);
const Code& code = Code::Handle(code_);
const Instructions& instrs = Instructions::Handle(code.instructions());
- Isolate* isolate = Isolate::Current();
{
WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
switch (breakpoint_kind_) {
@@ -34,13 +33,13 @@
case RawPcDescriptors::kUnoptStaticCall: {
saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
CodePatcher::PatchStaticCallAt(
- pc_, code, isolate->stub_code()->ICCallBreakpointEntryPoint());
+ pc_, code, StubCode::ICCallBreakpoint_entry()->EntryPoint());
break;
}
case RawPcDescriptors::kRuntimeCall: {
saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
CodePatcher::PatchStaticCallAt(
- pc_, code, isolate->stub_code()->RuntimeCallBreakpointEntryPoint());
+ pc_, code, StubCode::RuntimeCallBreakpoint_entry()->EntryPoint());
break;
}
default:
diff --git a/runtime/vm/debugger_mips.cc b/runtime/vm/debugger_mips.cc
index cd661db..651714b 100644
--- a/runtime/vm/debugger_mips.cc
+++ b/runtime/vm/debugger_mips.cc
@@ -20,15 +20,14 @@
void CodeBreakpoint::PatchCode() {
ASSERT(!is_enabled_);
- StubCode* stub_code = Isolate::Current()->stub_code();
uword stub_target = 0;
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = stub_code->ICCallBreakpointEntryPoint();
+ stub_target = StubCode::ICCallBreakpoint_entry()->EntryPoint();
break;
case RawPcDescriptors::kRuntimeCall:
- stub_target = stub_code->RuntimeCallBreakpointEntryPoint();
+ stub_target = StubCode::RuntimeCallBreakpoint_entry()->EntryPoint();
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/debugger_x64.cc b/runtime/vm/debugger_x64.cc
index 39b1ac1..531876d 100644
--- a/runtime/vm/debugger_x64.cc
+++ b/runtime/vm/debugger_x64.cc
@@ -22,15 +22,14 @@
void CodeBreakpoint::PatchCode() {
ASSERT(!is_enabled_);
- StubCode* stub_code = Isolate::Current()->stub_code();
uword stub_target = 0;
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = stub_code->ICCallBreakpointEntryPoint();
+ stub_target = StubCode::ICCallBreakpoint_entry()->EntryPoint();
break;
case RawPcDescriptors::kRuntimeCall:
- stub_target = stub_code->RuntimeCallBreakpointEntryPoint();
+ stub_target = StubCode::RuntimeCallBreakpoint_entry()->EntryPoint();
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index fa2e441..9f79640 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -220,7 +220,7 @@
#else
// Prepare for unwinding frames by destroying all the stack resources
// in the previous frames.
- StackResource::Unwind(thread->isolate());
+ StackResource::Unwind(thread);
// Call a stub to set up the exception object in kExceptionObjectReg,
// to set up the stacktrace object in kStackTraceObjectReg, and to
@@ -228,7 +228,7 @@
typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*,
Thread*);
ExcpHandler func = reinterpret_cast<ExcpHandler>(
- StubCode::JumpToExceptionHandlerEntryPoint());
+ StubCode::JumpToExceptionHandler_entry()->EntryPoint());
// Unpoison the stack before we tear it down in the generated stub code.
uword current_sp = Isolate::GetCurrentStackPointer() - 1024;
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 9457956..ce0fb5a 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -38,8 +38,11 @@
DEFINE_FLAG(bool, support_debugger, true, "Emit code needed for debugging");
DEFINE_FLAG(bool, trace_type_check_elimination, false,
"Trace type check elimination at compile time.");
+DEFINE_FLAG(bool, precompile_collect_closures, false,
+ "Collect all closure functions referenced from compiled code.");
DECLARE_FLAG(int, optimization_counter_threshold);
+DECLARE_FLAG(bool, profile_vm);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
DECLARE_FLAG(bool, use_field_guards);
@@ -2664,8 +2667,27 @@
}
+// TODO(rmacnak): De-dup closures in inlined-finally and track down other
+// stragglers to use Class::closures instead.
+static void CollectClosureFunction(const Function& function) {
+ if (function.HasCode()) return;
+
+ Isolate* isolate = Isolate::Current();
+ if (isolate->collected_closures() == GrowableObjectArray::null()) {
+ isolate->set_collected_closures(
+ GrowableObjectArray::Handle(GrowableObjectArray::New()));
+ }
+ const GrowableObjectArray& functions =
+ GrowableObjectArray::Handle(isolate, isolate->collected_closures());
+ functions.Add(function);
+}
+
+
void EffectGraphVisitor::VisitClosureNode(ClosureNode* node) {
const Function& function = node->function();
+ if (FLAG_precompile_collect_closures) {
+ CollectClosureFunction(function);
+ }
if (function.IsImplicitStaticClosureFunction()) {
const Instance& closure =
@@ -4762,6 +4784,9 @@
FlowGraph* FlowGraphBuilder::BuildGraph() {
+ VMTagScope tagScope(Thread::Current()->isolate(),
+ VMTag::kCompileFlowGraphBuilderTagId,
+ FLAG_profile_vm);
if (FLAG_print_ast) {
// Print the function ast before IL generation.
AstPrinter::PrintFunctionNodes(parsed_function());
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 1efd006..c7d3215 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -66,6 +66,7 @@
DECLARE_FLAG(bool, use_cha_deopt);
DECLARE_FLAG(bool, use_osr);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
+DECLARE_FLAG(bool, precompile_collect_closures);
static void NooptModeHandler(bool value) {
@@ -103,6 +104,27 @@
"Run fast unoptimized code only.");
+DECLARE_FLAG(bool, lazy_dispatchers);
+DECLARE_FLAG(bool, interpret_irregexp);
+DECLARE_FLAG(bool, enable_mirrors);
+
+
+static void PrecompileModeHandler(bool value) {
+ if (value) {
+ NooptModeHandler(true);
+ FLAG_lazy_dispatchers = false;
+ FLAG_interpret_irregexp = true;
+ FLAG_enable_mirrors = false;
+ FLAG_precompile_collect_closures = true;
+ }
+}
+
+
+DEFINE_FLAG_HANDLER(PrecompileModeHandler,
+ precompile,
+ "Precompilation mode");
+
+
// Assign locations to incoming arguments, i.e., values pushed above spill slots
// with PushArgument. Recursively allocates from outermost to innermost
// environment.
@@ -405,7 +427,7 @@
intptr_t inlining_id;
IntervalStruct(intptr_t s, intptr_t id) : start(s), inlining_id(id) {}
void Dump() {
- OS::Print("start: %" Px " id: %" Pd "", start, inlining_id);
+ ISL_Print("start: 0x%" Px " iid: %" Pd " ", start, inlining_id);
}
};
@@ -450,8 +472,7 @@
// Compose intervals.
if (instr->has_inlining_id() && is_optimizing()) {
if (prev_inlining_id != instr->inlining_id()) {
- intervals.Add(IntervalStruct(prev_offset,
- prev_inlining_id));
+ intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
prev_offset = assembler()->CodeSize();
prev_inlining_id = instr->inlining_id();
if (prev_inlining_id > max_inlining_id) {
@@ -460,8 +481,7 @@
}
}
if (FLAG_code_comments ||
- FLAG_disassemble ||
- FLAG_disassemble_optimized) {
+ FLAG_disassemble || FLAG_disassemble_optimized) {
if (FLAG_source_lines) {
EmitSourceLine(instr);
}
@@ -496,6 +516,7 @@
}
if (is_optimizing()) {
+ LogBlock lb(Isolate::Current());
intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
inlined_code_intervals_ =
Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld);
@@ -504,13 +525,14 @@
Smi& inline_id = Smi::Handle();
for (intptr_t i = 0; i < intervals.length(); i++) {
if (FLAG_trace_inlining_intervals && is_optimizing()) {
- const Function* function =
- inline_id_to_function_.At(intervals[i].inlining_id);
+ const Function& function =
+ *inline_id_to_function_.At(intervals[i].inlining_id);
intervals[i].Dump();
- OS::Print(" %s parent %" Pd "\n",
- function->ToQualifiedCString(),
- caller_inline_id_[intervals[i].inlining_id]);
+ ISL_Print(" parent iid %" Pd " %s\n",
+ caller_inline_id_[intervals[i].inlining_id],
+ function.ToQualifiedCString());
}
+
const intptr_t id = intervals[i].inlining_id;
start_h = Smi::New(intervals[i].start);
inline_id = Smi::New(id);
@@ -519,23 +541,24 @@
const intptr_t p = i * Code::kInlIntNumEntries;
inlined_code_intervals_.SetAt(p + Code::kInlIntStart, start_h);
inlined_code_intervals_.SetAt(p + Code::kInlIntInliningId, inline_id);
- inlined_code_intervals_.SetAt(
- p + Code::kInlIntCallerId, caller_inline_id);
}
}
set_current_block(NULL);
if (FLAG_trace_inlining_intervals && is_optimizing()) {
- OS::Print("Intervals:\n");
+ LogBlock lb(Isolate::Current());
+ ISL_Print("Intervals:\n");
+ for (intptr_t cc = 0; cc < caller_inline_id_.length(); cc++) {
+ ISL_Print(" iid: %" Pd " caller iid: %" Pd "\n",
+ cc, caller_inline_id_[cc]);
+ }
Smi& temp = Smi::Handle();
for (intptr_t i = 0; i < inlined_code_intervals_.Length();
i += Code::kInlIntNumEntries) {
temp ^= inlined_code_intervals_.At(i + Code::kInlIntStart);
ASSERT(!temp.IsNull());
- OS::Print("% " Pd " start: %" Px " ", i, temp.Value());
+ ISL_Print("% " Pd " start: 0x%" Px " ", i, temp.Value());
temp ^= inlined_code_intervals_.At(i + Code::kInlIntInliningId);
- OS::Print("inl-id: %" Pd " ", temp.Value());
- temp ^= inlined_code_intervals_.At(i + Code::kInlIntCallerId);
- OS::Print("caller-id: %" Pd " \n", temp.Value());
+ ISL_Print("iid: %" Pd " ", temp.Value());
}
}
}
@@ -1049,8 +1072,6 @@
return;
}
ASSERT(!ic_data.IsNull());
- uword label_address = 0;
- StubCode* stub_code = isolate()->stub_code();
if (is_optimizing() && (ic_data.NumberOfUsedChecks() == 0)) {
// Emit IC call that will count and thus may need reoptimization at
// function entry.
@@ -1059,17 +1080,18 @@
|| flow_graph().IsCompiledForOsr());
switch (ic_data.NumArgsTested()) {
case 1:
- label_address = stub_code->OneArgOptimizedCheckInlineCacheEntryPoint();
- break;
+ EmitOptimizedInstanceCall(
+ *StubCode::OneArgOptimizedCheckInlineCache_entry(), ic_data,
+ argument_count, deopt_id, token_pos, locs);
+ return;
case 2:
- label_address = stub_code->TwoArgsOptimizedCheckInlineCacheEntryPoint();
- break;
+ EmitOptimizedInstanceCall(
+ *StubCode::TwoArgsOptimizedCheckInlineCache_entry(), ic_data,
+ argument_count, deopt_id, token_pos, locs);
+ return;
default:
UNIMPLEMENTED();
}
- ExternalLabel target_label(label_address);
- EmitOptimizedInstanceCall(&target_label, ic_data,
- argument_count, deopt_id, token_pos, locs);
return;
}
@@ -1086,17 +1108,18 @@
switch (ic_data.NumArgsTested()) {
case 1:
- label_address = stub_code->OneArgCheckInlineCacheEntryPoint();
+ EmitInstanceCall(
+ *StubCode::OneArgCheckInlineCache_entry(), ic_data, argument_count,
+ deopt_id, token_pos, locs);
break;
case 2:
- label_address = stub_code->TwoArgsCheckInlineCacheEntryPoint();
+ EmitInstanceCall(
+ *StubCode::TwoArgsCheckInlineCache_entry(), ic_data, argument_count,
+ deopt_id, token_pos, locs);
break;
default:
UNIMPLEMENTED();
}
- ExternalLabel target_label(label_address);
- EmitInstanceCall(&target_label, ic_data, argument_count,
- deopt_id, token_pos, locs);
}
@@ -1678,6 +1701,21 @@
}
+RawArray* FlowGraphCompiler::CallerInliningIdMap() const {
+ if (caller_inline_id_.length() == 0) {
+ return Object::empty_array().raw();
+ }
+ const Array& res = Array::Handle(
+ Array::New(caller_inline_id_.length(), Heap::kOld));
+ Smi& smi = Smi::Handle();
+ for (intptr_t i = 0; i < caller_inline_id_.length(); i++) {
+ smi = Smi::New(caller_inline_id_[i]);
+ res.SetAt(i, smi);
+ }
+ return res.raw();
+}
+
+
void FlowGraphCompiler::EmitPolymorphicInstanceCall(
const ICData& ic_data,
intptr_t argument_count,
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 2ea19ee..536720e 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -337,13 +337,13 @@
LocationSummary* locs);
void GenerateCall(intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs);
void GenerateDartCall(intptr_t deopt_id,
intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs);
@@ -393,14 +393,14 @@
static int32_t EdgeCounterIncrementSizeInBytes();
#endif // !TARGET_ARCH_ARM64 && !TARGET_ARCH_MIPS
- void EmitOptimizedInstanceCall(ExternalLabel* target_label,
+ void EmitOptimizedInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs);
- void EmitInstanceCall(ExternalLabel* target_label,
+ void EmitInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
@@ -539,6 +539,8 @@
RawArray* InliningIdToFunction() const;
+ RawArray* CallerInliningIdMap() const;
+
private:
friend class CheckStackOverflowSlowPath; // For pending_deoptimization_env_.
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index d169b8d..f7b1fb4 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -67,14 +67,13 @@
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
- assembler()->set_allow_constant_pool(false);
+ ASSERT(!assembler()->constant_pool_allowed());
}
void FlowGraphCompiler::ExitIntrinsicMode() {
ASSERT(intrinsic_mode());
intrinsic_mode_ = false;
- assembler()->set_allow_constant_pool(true);
}
@@ -99,15 +98,17 @@
// The real frame starts here.
builder->MarkFrameStart();
+ Zone* zone = compiler->zone();
+
// Current PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(Function::Handle(current->code().function()),
+ builder->AddReturnAddress(Function::Handle(zone, current->code().function()),
deopt_id(),
slot_ix++);
// Callee's PC marker is not used anymore. Pass Function::null() to set to 0.
- builder->AddPcMarker(Function::Handle(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone), slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -125,17 +126,19 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPp(
+ Function::Handle(zone, current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(Function::Handle(current->code().function()),
- Isolate::ToDeoptAfter(current->deopt_id()),
- slot_ix++);
+ builder->AddReturnAddress(
+ Function::Handle(zone, current->code().function()),
+ Isolate::ToDeoptAfter(current->deopt_id()),
+ slot_ix++);
// PC marker.
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
@@ -168,7 +171,7 @@
builder->AddCallerPc(slot_ix++);
// PC marker.
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
// For the outermost environment, set the incoming arguments.
@@ -194,12 +197,11 @@
ASSERT(deopt_env() != NULL);
- StubCode* stub_code = compiler->isolate()->stub_code();
// LR may be live. It will be clobbered by BranchLink, so cache it in IP.
// It will be restored at the top of the deoptimization stub, specifically in
// GenerateDeoptimizationSequence in stub_code_arm.cc.
__ mov(IP, Operand(LR));
- __ BranchLink(&stub_code->DeoptimizeLabel());
+ __ BranchLink(*StubCode::Deoptimize_entry());
set_pc_offset(assem->CodeSize());
#undef __
}
@@ -235,20 +237,19 @@
ASSERT(instance_reg == R0);
ASSERT(temp_reg == kNoRegister); // Unused on ARM.
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- StubCode* stub_code = isolate()->stub_code();
+ SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
__ LoadUniqueObject(R2, type_test_cache);
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
__ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
- __ BranchLink(&stub_code->Subtype1TestCacheLabel());
+ __ BranchLink(*StubCode::Subtype1TestCache_entry());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
__ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
- __ BranchLink(&stub_code->Subtype2TestCacheLabel());
+ __ BranchLink(*StubCode::Subtype2TestCache_entry());
} else if (test_kind == kTestTypeThreeArgs) {
ASSERT(type_arguments_reg == R1);
- __ BranchLink(&stub_code->Subtype3TestCacheLabel());
+ __ BranchLink(*StubCode::Subtype3TestCache_entry());
} else {
UNREACHABLE();
}
@@ -271,11 +272,11 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
const Register kInstanceReg = R0;
- Error& malformed_error = Error::Handle();
- const Type& int_type = Type::Handle(Type::IntType());
+ Error& malformed_error = Error::Handle(zone());
+ const Type& int_type = Type::Handle(zone(), Type::IntType());
const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error);
// Malformed type should have been handled at graph construction time.
ASSERT(smi_is_ok || malformed_error.IsNull());
@@ -289,7 +290,7 @@
const intptr_t num_type_params = type_class.NumTypeParameters();
const intptr_t from_index = num_type_args - num_type_params;
const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(type.arguments());
+ TypeArguments::ZoneHandle(zone(), type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(from_index, num_type_params);
// Signature class is an instantiated parameterized type.
@@ -310,12 +311,12 @@
// If one type argument only, check if type argument is Object or dynamic.
if (type_arguments.Length() == 1) {
const AbstractType& tp_argument = AbstractType::ZoneHandle(
- type_arguments.TypeAt(0));
+ zone(), type_arguments.TypeAt(0));
ASSERT(!tp_argument.IsMalformed());
if (tp_argument.IsType()) {
ASSERT(tp_argument.HasResolvedTypeClass());
// Check if type argument is dynamic or Object.
- const Type& object_type = Type::Handle(Type::ObjectType());
+ const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(tp_argument, NULL)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@@ -361,16 +362,16 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::Handle(type.type_class());
+ const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
const Register kInstanceReg = R0;
__ tst(kInstanceReg, Operand(kSmiTagMask));
// If instance is Smi, check directly.
- const Class& smi_class = Class::Handle(Smi::Class());
- if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ const Class& smi_class = Class::Handle(zone(), Smi::Class());
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()),
type_class,
- TypeArguments::Handle(),
+ TypeArguments::Handle(zone()),
NULL)) {
__ b(is_instance_lbl, EQ);
} else {
@@ -399,7 +400,7 @@
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
- if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
+ if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) {
GenerateNumberTypeCheck(
kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
return false;
@@ -468,18 +469,18 @@
FieldAddress(R1, TypeArguments::type_at_offset(type_param.index())));
// R2: concrete type of type.
// Check if type argument is dynamic.
- __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()));
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::DynamicType()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType()));
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType()));
__ b(is_instance_lbl, EQ);
// For Smi check quickly against int and num interfaces.
Label not_smi;
__ tst(R0, Operand(kSmiTagMask)); // Value is Smi?
__ b(¬_smi, NE);
- __ CompareObject(R2, Type::ZoneHandle(Type::IntType()));
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R2, Type::ZoneHandle(Type::Number()));
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number()));
__ b(is_instance_lbl, EQ);
// Smi must be handled in runtime.
Label fall_through;
@@ -492,7 +493,7 @@
const Register kTypeArgumentsReg = R1;
const Register kTempReg = kNoRegister;
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(
+ SubtypeTestCache::ZoneHandle(zone(),
GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
kInstanceReg,
kTypeArgumentsReg,
@@ -543,7 +544,7 @@
return SubtypeTestCache::null();
}
if (type.IsInstantiated()) {
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
// A class equality check is only applicable with a dst type of a
// non-parameterized class, non-signature class, or with a raw dst type of
// a parameterized class.
@@ -612,7 +613,7 @@
}
// Generate inline instanceof test.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, type,
&is_instance, &is_not_instance);
@@ -707,7 +708,7 @@
}
// Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, dst_type,
&is_assignable, &runtime_call);
@@ -864,7 +865,7 @@
__ Bind(&load_default_value);
// Load R5 with default argument.
const Object& value = Object::ZoneHandle(
- parsed_function().default_parameter_values().At(
+ zone(), parsed_function().default_parameter_values().At(
param_pos - num_fixed_params));
__ LoadObject(R5, value);
__ Bind(&assign_optional_parameter);
@@ -900,7 +901,7 @@
__ b(&next_parameter, GT);
// Load R5 with default argument.
const Object& value = Object::ZoneHandle(
- parsed_function().default_parameter_values().At(i));
+ zone(), parsed_function().default_parameter_values().At(i));
__ LoadObject(R5, value);
// Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
@@ -922,8 +923,12 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
+ ASSERT(assembler()->constant_pool_allowed());
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ Branch(&isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ // Do not use caller's pool ptr in branch.
+ ASSERT(!assembler()->constant_pool_allowed());
+ __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
+ __ set_constant_pool_allowed(true);
// The noSuchMethod call may return to the caller, but not here.
} else if (check_correct_named_args) {
__ Stop("Wrong arguments");
@@ -983,7 +988,6 @@
function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = R6;
- StubCode* stub_code = isolate()->stub_code();
// The pool pointer is not setup before entering the Dart frame.
// Preserve PP of caller.
@@ -994,6 +998,7 @@
__ LoadObject(function_reg, function); // Uses PP.
// Restore PP of caller.
__ mov(PP, Operand(R7));
+ __ set_constant_pool_allowed(false);
// Patch point is after the eventually inlined function object.
entry_patch_pc_offset_ = assembler()->CodeSize();
@@ -1009,7 +1014,7 @@
}
__ CompareImmediate(R7, GetOptimizationThreshold());
ASSERT(function_reg == R6);
- __ Branch(&stub_code->OptimizeFunctionLabel(), GE);
+ __ Branch(*StubCode::OptimizeFunction_entry(), GE);
} else if (!flow_graph().IsCompiledForOsr()) {
entry_patch_pc_offset_ = assembler()->CodeSize();
}
@@ -1040,13 +1045,13 @@
TryIntrinsify();
EmitFrameEntry();
+ ASSERT(assembler()->constant_pool_allowed());
const Function& function = parsed_function().function();
const int num_fixed_params = function.num_fixed_parameters();
const int num_copied_params = parsed_function().num_copied_params();
const int num_locals = parsed_function().num_stack_locals();
- StubCode* stub_code = isolate()->stub_code();
// We check the number of passed arguments when we have to copy them due to
// the presence of optional parameters.
@@ -1073,8 +1078,12 @@
__ b(&correct_num_arguments, EQ);
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
+ ASSERT(assembler()->constant_pool_allowed());
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ Branch(&isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ // Do not use caller's pool ptr in branch.
+ ASSERT(!assembler()->constant_pool_allowed());
+ __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
+ __ set_constant_pool_allowed(true);
// The noSuchMethod call may return to the caller, but not here.
} else {
__ Stop("Wrong number of arguments");
@@ -1125,24 +1134,25 @@
VisitBlocks();
__ bkpt(0);
+ ASSERT(assembler()->constant_pool_allowed());
GenerateDeferredCode();
// Emit function patching code. This will be swapped with the first 3
// instructions at entry point.
patch_code_pc_offset_ = assembler()->CodeSize();
- __ BranchPatchable(&stub_code->FixCallersTargetLabel());
+ __ BranchPatchable(*StubCode::FixCallersTarget_entry());
if (is_optimizing()) {
lazy_deopt_pc_offset_ = assembler()->CodeSize();
- __ Branch(&stub_code->DeoptimizeLazyLabel());
+ __ Branch(*StubCode::DeoptimizeLazy_entry());
}
}
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(label);
+ __ BranchLinkPatchable(stub_entry);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}
@@ -1150,10 +1160,10 @@
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(label);
+ __ BranchLinkPatchable(stub_entry);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
// Marks either the continuation point in unoptimized code or the
@@ -1201,8 +1211,9 @@
// overflow; and though we do not reset the counters when we optimize or
// deoptimize, there is a bound on the number of
// optimization/deoptimization cycles we will attempt.
- const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
- counter.SetAt(0, Smi::Handle(Smi::New(0)));
+ ASSERT(assembler_->constant_pool_allowed());
+ const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld));
+ counter.SetAt(0, Smi::Handle(zone(), Smi::New(0)));
__ Comment("Edge counter");
__ LoadUniqueObject(R0, counter);
intptr_t increment_start = assembler_->CodeSize();
@@ -1233,13 +1244,13 @@
void FlowGraphCompiler::EmitOptimizedInstanceCall(
- ExternalLabel* target_label,
+ const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
// to inlining in optimized code, that function may not correspond to the
@@ -1251,24 +1262,24 @@
__ LoadUniqueObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
}
-void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
+void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
__ LoadUniqueObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
@@ -1282,12 +1293,12 @@
intptr_t token_pos,
LocationSummary* locs) {
MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
- const String& name = String::Handle(ic_data.target_name());
+ const String& name = String::Handle(zone(), ic_data.target_name());
const Array& arguments_descriptor =
- Array::ZoneHandle(ic_data.arguments_descriptor());
+ Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache =
- MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
+ const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
+ zone(), table->Lookup(name, arguments_descriptor));
const Register receiverR = R0;
const Register cacheR = R1;
const Register targetR = R1;
@@ -1295,8 +1306,7 @@
__ LoadObject(cacheR, cache);
if (FLAG_use_megamorphic_stub) {
- StubCode* stub_code = isolate()->stub_code();
- __ BranchLink(&stub_code->MegamorphicLookupLabel());
+ __ BranchLink(*StubCode::MegamorphicLookup_entry());
} else {
StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR);
}
@@ -1325,14 +1335,12 @@
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- StubCode* stub_code = isolate()->stub_code();
- const uword label_address =
- stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
- ExternalLabel target_label(label_address);
+ const StubEntry* stub_entry =
+ StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- &target_label,
+ *stub_entry,
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
@@ -1346,13 +1354,12 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- StubCode* stub_code = isolate()->stub_code();
__ LoadObject(R4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_pos,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
AddStaticCallTarget(function);
@@ -1366,16 +1373,15 @@
bool needs_number_check,
intptr_t token_pos) {
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint());
__ Push(reg);
__ PushObject(obj);
if (is_optimizing()) {
__ BranchLinkPatchable(
- &stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
__ BranchLinkPatchable(
- &stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1397,15 +1403,14 @@
bool needs_number_check,
intptr_t token_pos) {
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ Push(left);
__ Push(right);
if (is_optimizing()) {
__ BranchLinkPatchable(
- &stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
__ BranchLinkPatchable(
- &stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1522,9 +1527,8 @@
ASSERT(is_optimizing());
__ Comment("EmitTestAndCall");
const Array& arguments_descriptor =
- Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
- argument_names));
- StubCode* stub_code = isolate()->stub_code();
+ Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count,
+ argument_names));
// Load receiver into R0.
__ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
@@ -1548,10 +1552,10 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
- const Function& function = Function::Handle(ic_data.GetTargetAt(0));
+ const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0));
AddStaticCallTarget(function);
__ Drop(argument_count);
if (kNumChecks > 1) {
@@ -1589,7 +1593,7 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
const Function& function = *sorted[i].target;
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index f951807..a473953 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -64,14 +64,13 @@
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
- assembler()->set_allow_constant_pool(false);
+ ASSERT(!assembler()->constant_pool_allowed());
}
void FlowGraphCompiler::ExitIntrinsicMode() {
ASSERT(intrinsic_mode());
intrinsic_mode_ = false;
- assembler()->set_allow_constant_pool(true);
}
@@ -96,11 +95,13 @@
// The real frame starts here.
builder->MarkFrameStart();
+ Zone* zone = compiler->zone();
+
// Current PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
- builder->AddPcMarker(Function::Handle(), slot_ix++);
+ builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(Function::Handle(current->code().function()),
+ builder->AddReturnAddress(Function::Handle(zone, current->code().function()),
deopt_id(),
slot_ix++);
@@ -120,16 +121,18 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPp(Function::Handle(
+ zone, current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(Function::Handle(current->code().function()),
- Isolate::ToDeoptAfter(current->deopt_id()),
- slot_ix++);
+ builder->AddReturnAddress(
+ Function::Handle(zone, current->code().function()),
+ Isolate::ToDeoptAfter(current->deopt_id()),
+ slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
// we must read them from the previous environment.
@@ -158,7 +161,7 @@
// For the outermost environment, set caller PC, caller PP, and caller FP.
builder->AddCallerPp(slot_ix++);
// PC marker.
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
builder->AddCallerFp(slot_ix++);
builder->AddCallerPc(slot_ix++);
@@ -186,8 +189,7 @@
ASSERT(deopt_env() != NULL);
- StubCode* stub_code = compiler->isolate()->stub_code();
- __ BranchLink(&stub_code->DeoptimizeLabel(), PP);
+ __ BranchLink(*StubCode::Deoptimize_entry());
set_pc_offset(assem->CodeSize());
#undef __
}
@@ -201,9 +203,9 @@
Label* is_true,
Label* is_false) {
Label fall_through;
- __ CompareObject(bool_register, Object::null_object(), PP);
+ __ CompareObject(bool_register, Object::null_object());
__ b(&fall_through, EQ);
- __ CompareObject(bool_register, Bool::True(), PP);
+ __ CompareObject(bool_register, Bool::True());
__ b(is_true, EQ);
__ b(is_false);
__ Bind(&fall_through);
@@ -222,20 +224,19 @@
ASSERT(instance_reg == R0);
ASSERT(temp_reg == kNoRegister); // Unused on ARM.
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- StubCode* stub_code = isolate()->stub_code();
- __ LoadUniqueObject(R2, type_test_cache, PP);
+ SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
+ __ LoadUniqueObject(R2, type_test_cache);
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
- __ LoadObject(R1, Object::null_object(), PP);
- __ BranchLink(&stub_code->Subtype1TestCacheLabel(), PP);
+ __ LoadObject(R1, Object::null_object());
+ __ BranchLink(*StubCode::Subtype1TestCache_entry());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
- __ LoadObject(R1, Object::null_object(), PP);
- __ BranchLink(&stub_code->Subtype2TestCacheLabel(), PP);
+ __ LoadObject(R1, Object::null_object());
+ __ BranchLink(*StubCode::Subtype2TestCache_entry());
} else if (test_kind == kTestTypeThreeArgs) {
ASSERT(type_arguments_reg == R1);
- __ BranchLink(&stub_code->Subtype3TestCacheLabel(), PP);
+ __ BranchLink(*StubCode::Subtype3TestCache_entry());
} else {
UNREACHABLE();
}
@@ -258,11 +259,11 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
const Register kInstanceReg = R0;
- Error& malformed_error = Error::Handle();
- const Type& int_type = Type::Handle(Type::IntType());
+ Error& malformed_error = Error::Handle(zone());
+ const Type& int_type = Type::Handle(zone(), Type::IntType());
const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error);
// Malformed type should have been handled at graph construction time.
ASSERT(smi_is_ok || malformed_error.IsNull());
@@ -276,7 +277,7 @@
const intptr_t num_type_params = type_class.NumTypeParameters();
const intptr_t from_index = num_type_args - num_type_params;
const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(type.arguments());
+ TypeArguments::ZoneHandle(zone(), type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(from_index, num_type_params);
// Signature class is an instantiated parameterized type.
@@ -284,8 +285,8 @@
if (is_raw_type) {
const Register kClassIdReg = R2;
// dynamic type argument, check only classes.
- __ LoadClassId(kClassIdReg, kInstanceReg, PP);
- __ CompareImmediate(kClassIdReg, type_class.id(), PP);
+ __ LoadClassId(kClassIdReg, kInstanceReg);
+ __ CompareImmediate(kClassIdReg, type_class.id());
__ b(is_instance_lbl, EQ);
// List is a very common case.
if (IsListClass(type_class)) {
@@ -297,12 +298,12 @@
// If one type argument only, check if type argument is Object or dynamic.
if (type_arguments.Length() == 1) {
const AbstractType& tp_argument = AbstractType::ZoneHandle(
- type_arguments.TypeAt(0));
+ zone(), type_arguments.TypeAt(0));
ASSERT(!tp_argument.IsMalformed());
if (tp_argument.IsType()) {
ASSERT(tp_argument.HasResolvedTypeClass());
// Check if type argument is dynamic or Object.
- const Type& object_type = Type::Handle(Type::ObjectType());
+ const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(tp_argument, NULL)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@@ -329,7 +330,7 @@
Label* is_equal_lbl,
Label* is_not_equal_lbl) {
for (intptr_t i = 0; i < class_ids.length(); i++) {
- __ CompareImmediate(class_id_reg, class_ids[i], PP);
+ __ CompareImmediate(class_id_reg, class_ids[i]);
__ b(is_equal_lbl, EQ);
}
__ b(is_not_equal_lbl);
@@ -348,16 +349,16 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::Handle(type.type_class());
+ const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
const Register kInstanceReg = R0;
__ tsti(kInstanceReg, Immediate(kSmiTagMask));
// If instance is Smi, check directly.
- const Class& smi_class = Class::Handle(Smi::Class());
- if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ const Class& smi_class = Class::Handle(zone(), Smi::Class());
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()),
type_class,
- TypeArguments::Handle(),
+ TypeArguments::Handle(zone()),
NULL)) {
__ b(is_instance_lbl, EQ);
} else {
@@ -365,28 +366,28 @@
}
// Compare if the classes are equal.
const Register kClassIdReg = R2;
- __ LoadClassId(kClassIdReg, kInstanceReg, PP);
- __ CompareImmediate(kClassIdReg, type_class.id(), PP);
+ __ LoadClassId(kClassIdReg, kInstanceReg);
+ __ CompareImmediate(kClassIdReg, type_class.id());
__ b(is_instance_lbl, EQ);
// See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
// interfaces.
// Bool interface can be implemented only by core class Bool.
if (type.IsBoolType()) {
- __ CompareImmediate(kClassIdReg, kBoolCid, PP);
+ __ CompareImmediate(kClassIdReg, kBoolCid);
__ b(is_instance_lbl, EQ);
__ b(is_not_instance_lbl);
return false;
}
if (type.IsFunctionType()) {
// Check if instance is a closure.
- __ LoadClassById(R3, kClassIdReg, PP);
- __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset(), PP);
- __ CompareObject(R3, Object::null_object(), PP);
+ __ LoadClassById(R3, kClassIdReg);
+ __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset());
+ __ CompareObject(R3, Object::null_object());
__ b(is_instance_lbl, NE);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
- if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
+ if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) {
GenerateNumberTypeCheck(
kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
return false;
@@ -414,12 +415,12 @@
Label* is_not_instance_lbl) {
__ Comment("Subtype1TestCacheLookup");
const Register kInstanceReg = R0;
- __ LoadClass(R1, kInstanceReg, PP);
+ __ LoadClass(R1, kInstanceReg);
// R1: instance class.
// Check immediate superclass equality.
- __ LoadFieldFromOffset(R2, R1, Class::super_type_offset(), PP);
- __ LoadFieldFromOffset(R2, R2, Type::type_class_offset(), PP);
- __ CompareObject(R2, type_class, PP);
+ __ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
+ __ LoadFieldFromOffset(R2, R2, Type::type_class_offset());
+ __ CompareObject(R2, type_class);
__ b(is_instance_lbl, EQ);
const Register kTypeArgumentsReg = kNoRegister;
@@ -449,24 +450,24 @@
__ ldr(R1, Address(SP)); // Get instantiator type arguments.
// R1: instantiator type arguments.
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
- __ CompareObject(R1, Object::null_object(), PP);
+ __ CompareObject(R1, Object::null_object());
__ b(is_instance_lbl, EQ);
__ LoadFieldFromOffset(
- R2, R1, TypeArguments::type_at_offset(type_param.index()), PP);
+ R2, R1, TypeArguments::type_at_offset(type_param.index()));
// R2: concrete type of type.
// Check if type argument is dynamic.
- __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()), PP);
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::DynamicType()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType()), PP);
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType()));
__ b(is_instance_lbl, EQ);
// For Smi check quickly against int and num interfaces.
Label not_smi;
__ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi?
__ b(¬_smi, NE);
- __ CompareObject(R2, Type::ZoneHandle(Type::IntType()), PP);
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R2, Type::ZoneHandle(Type::Number()), PP);
+ __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number()));
__ b(is_instance_lbl, EQ);
// Smi must be handled in runtime.
Label fall_through;
@@ -479,7 +480,7 @@
const Register kTypeArgumentsReg = R1;
const Register kTempReg = kNoRegister;
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(
+ SubtypeTestCache::ZoneHandle(zone(),
GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
kInstanceReg,
kTypeArgumentsReg,
@@ -530,7 +531,7 @@
return SubtypeTestCache::null();
}
if (type.IsInstantiated()) {
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
// A class equality check is only applicable with a dst type of a
// non-parameterized class, non-signature class, or with a raw dst type of
// a parameterized class.
@@ -595,12 +596,12 @@
// We can only inline this null check if the type is instantiated at compile
// time, since an uninstantiated type at compile time could be Object or
// dynamic at run time.
- __ CompareObject(R0, Object::null_object(), PP);
+ __ CompareObject(R0, Object::null_object());
__ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ);
}
// Generate inline instanceof test.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, type,
&is_instance, &is_not_instance);
@@ -611,13 +612,13 @@
// Load instantiator (R2) and its type arguments (R1).
__ ldr(R1, Address(SP, 0 * kWordSize));
__ ldr(R2, Address(SP, 1 * kWordSize));
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ Push(R0); // Push the instance.
- __ PushObject(type, PP); // Push the type.
+ __ PushObject(type); // Push the type.
// Push instantiator (R2) and its type arguments (R1).
__ Push(R2);
__ Push(R1);
- __ LoadUniqueObject(R0, test_cache, PP);
+ __ LoadUniqueObject(R0, test_cache);
__ Push(R0);
GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
// Pop the parameters supplied to the runtime entry. The result of the
@@ -625,21 +626,21 @@
__ Drop(5);
if (negate_result) {
__ Pop(R1);
- __ LoadObject(R0, Bool::True(), PP);
+ __ LoadObject(R0, Bool::True());
__ CompareRegisters(R1, R0);
__ b(&done, NE);
- __ LoadObject(R0, Bool::False(), PP);
+ __ LoadObject(R0, Bool::False());
} else {
__ Pop(R0);
}
__ b(&done);
}
__ Bind(&is_not_instance);
- __ LoadObject(R0, Bool::Get(negate_result), PP);
+ __ LoadObject(R0, Bool::Get(negate_result));
__ b(&done);
__ Bind(&is_instance);
- __ LoadObject(R0, Bool::Get(!negate_result), PP);
+ __ LoadObject(R0, Bool::Get(!negate_result));
__ Bind(&done);
// Remove instantiator (R2) and its type arguments (R1).
__ Drop(2);
@@ -674,15 +675,15 @@
__ Push(R1);
// A null object is always assignable and is returned as result.
Label is_assignable, runtime_call;
- __ CompareObject(R0, Object::null_object(), PP);
+ __ CompareObject(R0, Object::null_object());
__ b(&is_assignable, EQ);
// Generate throw new TypeError() if the type is malformed or malbounded.
if (dst_type.IsMalformedOrMalbounded()) {
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ Push(R0); // Push the source object.
- __ PushObject(dst_name, PP); // Push the name of the destination.
- __ PushObject(dst_type, PP); // Push the type of the destination.
+ __ PushObject(dst_name); // Push the name of the destination.
+ __ PushObject(dst_type); // Push the type of the destination.
GenerateRuntimeCall(token_pos,
deopt_id,
kBadTypeErrorRuntimeEntry,
@@ -699,7 +700,7 @@
}
// Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, dst_type,
&is_assignable, &runtime_call);
@@ -707,14 +708,14 @@
// Load instantiator (R2) and its type arguments (R1).
__ ldr(R1, Address(SP));
__ ldr(R2, Address(SP, 1 * kWordSize));
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ Push(R0); // Push the source object.
- __ PushObject(dst_type, PP); // Push the type of the destination.
+ __ PushObject(dst_type); // Push the type of the destination.
// Push instantiator (R2) and its type arguments (R1).
__ Push(R2);
__ Push(R1);
- __ PushObject(dst_name, PP); // Push the name of the destination.
- __ LoadUniqueObject(R0, test_cache, PP);
+ __ PushObject(dst_name); // Push the name of the destination.
+ __ LoadUniqueObject(R0, test_cache);
__ Push(R0);
GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
@@ -760,20 +761,20 @@
const int max_num_pos_args = num_fixed_params + num_opt_pos_params;
__ LoadFieldFromOffset(
- R8, R4, ArgumentsDescriptor::positional_count_offset(), PP);
+ R8, R4, ArgumentsDescriptor::positional_count_offset());
// Check that min_num_pos_args <= num_pos_args.
Label wrong_num_arguments;
- __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args), PP);
+ __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args));
__ b(&wrong_num_arguments, LT);
// Check that num_pos_args <= max_num_pos_args.
- __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args), PP);
+ __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args));
__ b(&wrong_num_arguments, GT);
// Copy positional arguments.
// Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied
// to fp[kFirstLocalSlotFromFp - i].
- __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP);
+ __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
// Since R7 and R8 are Smi, use LSL 2 instead of LSL 3.
// Let R7 point to the last passed positional argument, i.e. to
// fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)].
@@ -783,7 +784,7 @@
// Let R6 point to the last copied positional argument, i.e. to
// fp[kFirstLocalSlotFromFp - (num_pos_args - 1)].
- __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize, PP);
+ __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize);
__ sub(R6, R6, Operand(R8, LSL, 2)); // R8 is a Smi.
__ SmiUntag(R8);
Label loop, loop_condition;
@@ -827,14 +828,14 @@
opt_param_position[i + 1] = pos;
}
// Generate code handling each optional parameter in alphabetical order.
- __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP);
+ __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
__ LoadFieldFromOffset(
- R8, R4, ArgumentsDescriptor::positional_count_offset(), PP);
+ R8, R4, ArgumentsDescriptor::positional_count_offset());
__ SmiUntag(R8);
// Let R7 point to the first passed argument, i.e. to
// fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi.
__ add(R7, FP, Operand(R7, LSL, 2));
- __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize, PP);
+ __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize);
// Let R6 point to the entry of the first named argument.
__ add(R6, R4, Operand(
ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag));
@@ -843,13 +844,13 @@
const int param_pos = opt_param_position[i];
// Check if this named parameter was passed in.
// Load R5 with the name of the argument.
- __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset(), PP);
+ __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset());
ASSERT(opt_param[i]->name().IsSymbol());
- __ CompareObject(R5, opt_param[i]->name(), PP);
+ __ CompareObject(R5, opt_param[i]->name());
__ b(&load_default_value, NE);
// Load R5 with passed-in argument at provided arg_pos, i.e. at
// fp[kParamEndSlotFromFp + num_args - arg_pos].
- __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset(), PP);
+ __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset());
// R5 is arg_pos as Smi.
// Point to next named entry.
__ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size()));
@@ -861,16 +862,16 @@
__ Bind(&load_default_value);
// Load R5 with default argument.
const Object& value = Object::ZoneHandle(
- parsed_function().default_parameter_values().At(
+ zone(), parsed_function().default_parameter_values().At(
param_pos - num_fixed_params));
- __ LoadObject(R5, value, PP);
+ __ LoadObject(R5, value);
__ Bind(&assign_optional_parameter);
// Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
// scope->VariableAt(i)->index(), because captured variables still need
// to be copied to the context that is not yet allocated.
const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
- __ StoreToOffset(R5, FP, computed_param_pos * kWordSize, PP);
+ __ StoreToOffset(R5, FP, computed_param_pos * kWordSize);
}
delete[] opt_param;
delete[] opt_param_position;
@@ -878,13 +879,13 @@
// Check that R6 now points to the null terminator in the arguments
// descriptor.
__ ldr(R5, Address(R6));
- __ CompareObject(R5, Object::null_object(), PP);
+ __ CompareObject(R5, Object::null_object());
__ b(&all_arguments_processed, EQ);
}
} else {
ASSERT(num_opt_pos_params > 0);
__ LoadFieldFromOffset(
- R8, R4, ArgumentsDescriptor::positional_count_offset(), PP);
+ R8, R4, ArgumentsDescriptor::positional_count_offset());
__ SmiUntag(R8);
for (int i = 0; i < num_opt_pos_params; i++) {
Label next_parameter;
@@ -892,22 +893,22 @@
// arguments have been passed, where k is param_pos, the position of this
// optional parameter in the formal parameter list.
const int param_pos = num_fixed_params + i;
- __ CompareImmediate(R8, param_pos, PP);
+ __ CompareImmediate(R8, param_pos);
__ b(&next_parameter, GT);
// Load R5 with default argument.
const Object& value = Object::ZoneHandle(
- parsed_function().default_parameter_values().At(i));
- __ LoadObject(R5, value, PP);
+ zone(), parsed_function().default_parameter_values().At(i));
+ __ LoadObject(R5, value);
// Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
// scope->VariableAt(i)->index(), because captured variables still need
// to be copied to the context that is not yet allocated.
const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
- __ StoreToOffset(R5, FP, computed_param_pos * kWordSize, PP);
+ __ StoreToOffset(R5, FP, computed_param_pos * kWordSize);
__ Bind(&next_parameter);
}
if (check_correct_named_args) {
- __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP);
+ __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
__ SmiUntag(R7);
// Check that R8 equals R7, i.e. no named arguments passed.
__ CompareRegisters(R8, R7);
@@ -917,9 +918,12 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
+ ASSERT(assembler()->constant_pool_allowed());
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ BranchPatchable(
- &isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ // Do not use caller's pool ptr in branch.
+ ASSERT(!assembler()->constant_pool_allowed());
+ __ BranchPatchable(*StubCode::CallClosureNoSuchMethod_entry());
+ __ set_constant_pool_allowed(true);
// The noSuchMethod call may return to the caller, but not here.
} else if (check_correct_named_args) {
__ Stop("Wrong arguments");
@@ -933,11 +937,11 @@
// an issue anymore.
// R4 : arguments descriptor array.
- __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset(), PP);
+ __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset());
__ SmiUntag(R8);
__ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize));
const Address original_argument_addr(R7, R8, UXTX, Address::Scaled);
- __ LoadObject(TMP, Object::null_object(), PP);
+ __ LoadObject(TMP, Object::null_object());
Label null_args_loop, null_args_loop_condition;
__ b(&null_args_loop_condition);
__ Bind(&null_args_loop);
@@ -953,8 +957,8 @@
// SP: receiver.
// Sequence node has one return node, its input is load field node.
__ Comment("Inlined Getter");
- __ LoadFromOffset(R0, SP, 0 * kWordSize, PP);
- __ LoadFromOffset(R0, R0, offset - kHeapObjectTag, PP);
+ __ LoadFromOffset(R0, SP, 0 * kWordSize);
+ __ LoadFromOffset(R0, R0, offset - kHeapObjectTag);
__ ret();
}
@@ -965,56 +969,48 @@
// SP+0: value.
// Sequence node has one store node and one return NULL node.
__ Comment("Inlined Setter");
- __ LoadFromOffset(R0, SP, 1 * kWordSize, PP); // Receiver.
- __ LoadFromOffset(R1, SP, 0 * kWordSize, PP); // Value.
- __ StoreIntoObjectOffset(R0, offset, R1, PP);
- __ LoadObject(R0, Object::null_object(), PP);
+ __ LoadFromOffset(R0, SP, 1 * kWordSize); // Receiver.
+ __ LoadFromOffset(R1, SP, 0 * kWordSize); // Value.
+ __ StoreIntoObjectOffset(R0, offset, R1);
+ __ LoadObject(R0, Object::null_object());
__ ret();
}
void FlowGraphCompiler::EmitFrameEntry() {
const Function& function = parsed_function().function();
- Register new_pp = kNoPP;
+ Register new_pp = kNoRegister;
if (CanOptimizeFunction() &&
function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = R6;
- StubCode* stub_code = isolate()->stub_code();
new_pp = R13;
-
- // Set up pool pointer in new_pp.
+ // The pool pointer is not setup before entering the Dart frame.
+ // Temporarily setup pool pointer for this dart function.
__ LoadPoolPointer(new_pp);
// Load function object using the callee's pool pointer.
- __ LoadObject(function_reg, function, new_pp);
+ __ LoadFunctionFromCalleePool(function_reg, function, new_pp);
// Patch point is after the eventually inlined function object.
entry_patch_pc_offset_ = assembler()->CodeSize();
__ LoadFieldFromOffset(
- R7, function_reg, Function::usage_counter_offset(), new_pp, kWord);
+ R7, function_reg, Function::usage_counter_offset(), kWord);
// Reoptimization of an optimized function is triggered by counting in
// IC stubs, but not at the entry of the function.
if (!is_optimizing()) {
__ add(R7, R7, Operand(1));
__ StoreFieldToOffset(
- R7, function_reg, Function::usage_counter_offset(), new_pp, kWord);
+ R7, function_reg, Function::usage_counter_offset(), kWord);
}
- __ CompareImmediate(R7, GetOptimizationThreshold(), new_pp);
+ __ CompareImmediate(R7, GetOptimizationThreshold());
ASSERT(function_reg == R6);
Label dont_optimize;
__ b(&dont_optimize, LT);
- __ Branch(&stub_code->OptimizeFunctionLabel(), new_pp);
+ __ Branch(*StubCode::OptimizeFunction_entry());
__ Bind(&dont_optimize);
} else if (!flow_graph().IsCompiledForOsr()) {
- // We have to load the PP here too because a load of an external label
- // may be patched at the AddCurrentDescriptor below.
- new_pp = R13;
-
- // Set up pool pointer in new_pp.
- __ LoadPoolPointer(new_pp);
-
entry_patch_pc_offset_ = assembler()->CodeSize();
}
__ Comment("Enter frame");
@@ -1044,13 +1040,13 @@
TryIntrinsify();
EmitFrameEntry();
+ ASSERT(assembler()->constant_pool_allowed());
const Function& function = parsed_function().function();
const int num_fixed_params = function.num_fixed_parameters();
const int num_copied_params = parsed_function().num_copied_params();
const int num_locals = parsed_function().num_stack_locals();
- StubCode* stub_code = isolate()->stub_code();
// We check the number of passed arguments when we have to copy them due to
// the presence of optional parameters.
@@ -1068,18 +1064,21 @@
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
Label correct_num_arguments, wrong_num_arguments;
- __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset(), PP);
- __ CompareImmediate(R0, Smi::RawValue(num_fixed_params), PP);
+ __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset());
+ __ CompareImmediate(R0, Smi::RawValue(num_fixed_params));
__ b(&wrong_num_arguments, NE);
__ LoadFieldFromOffset(R1, R4,
- ArgumentsDescriptor::positional_count_offset(), PP);
+ ArgumentsDescriptor::positional_count_offset());
__ CompareRegisters(R0, R1);
__ b(&correct_num_arguments, EQ);
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
+ ASSERT(assembler()->constant_pool_allowed());
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ BranchPatchable(
- &isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ // Do not use caller's pool ptr in branch.
+ ASSERT(!assembler()->constant_pool_allowed());
+ __ BranchPatchable(*StubCode::CallClosureNoSuchMethod_entry());
+ __ set_constant_pool_allowed(true);
// The noSuchMethod call may return to the caller, but not here.
} else {
__ Stop("Wrong number of arguments");
@@ -1107,22 +1106,22 @@
const intptr_t context_index =
parsed_function().current_context_var()->index();
if (num_locals > 1) {
- __ LoadObject(R0, Object::null_object(), PP);
+ __ LoadObject(R0, Object::null_object());
}
for (intptr_t i = 0; i < num_locals; ++i) {
// Subtract index i (locals lie at lower addresses than FP).
if (((slot_base - i) == context_index)) {
if (function.IsClosureFunction()) {
- __ StoreToOffset(CTX, FP, (slot_base - i) * kWordSize, PP);
+ __ StoreToOffset(CTX, FP, (slot_base - i) * kWordSize);
} else {
const Context& empty_context = Context::ZoneHandle(
zone(), isolate()->object_store()->empty_context());
- __ LoadObject(R1, empty_context, PP);
- __ StoreToOffset(R1, FP, (slot_base - i) * kWordSize, PP);
+ __ LoadObject(R1, empty_context);
+ __ StoreToOffset(R1, FP, (slot_base - i) * kWordSize);
}
} else {
ASSERT(num_locals > 1);
- __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize, PP);
+ __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize);
}
}
}
@@ -1130,25 +1129,26 @@
VisitBlocks();
__ brk(0);
+ ASSERT(assembler()->constant_pool_allowed());
GenerateDeferredCode();
// Emit function patching code. This will be swapped with the first 3
// instructions at entry point.
patch_code_pc_offset_ = assembler()->CodeSize();
- __ BranchPatchable(&stub_code->FixCallersTargetLabel());
+ __ BranchPatchable(*StubCode::FixCallersTarget_entry());
if (is_optimizing()) {
lazy_deopt_pc_offset_ = assembler()->CodeSize();
- __ BranchPatchable(&stub_code->DeoptimizeLazyLabel());
+ __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
}
}
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(label);
+ __ BranchLinkPatchable(stub_entry);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}
@@ -1156,10 +1156,10 @@
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(label);
+ __ BranchLinkPatchable(stub_entry);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
// Marks either the continuation point in unoptimized code or the
@@ -1204,24 +1204,25 @@
// overflow; and though we do not reset the counters when we optimize or
// deoptimize, there is a bound on the number of
// optimization/deoptimization cycles we will attempt.
- const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
- counter.SetAt(0, Smi::Handle(Smi::New(0)));
+ ASSERT(assembler_->constant_pool_allowed());
+ const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld));
+ counter.SetAt(0, Smi::Handle(zone(), Smi::New(0)));
__ Comment("Edge counter");
- __ LoadUniqueObject(R0, counter, PP);
- __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0), PP);
+ __ LoadUniqueObject(R0, counter);
+ __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0));
__ add(TMP, TMP, Operand(Smi::RawValue(1)));
- __ StoreFieldToOffset(TMP, R0, Array::element_offset(0), PP);
+ __ StoreFieldToOffset(TMP, R0, Array::element_offset(0));
}
void FlowGraphCompiler::EmitOptimizedInstanceCall(
- ExternalLabel* target_label,
+ const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
// to inlining in optimized code, that function may not correspond to the
@@ -1229,28 +1230,28 @@
// reoptimized and which counter needs to be incremented.
// Pass the function explicitly, it is used in IC stub.
- __ LoadObject(R6, parsed_function().function(), PP);
- __ LoadUniqueObject(R5, ic_data, PP);
+ __ LoadObject(R6, parsed_function().function());
+ __ LoadUniqueObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
}
-void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
+void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
- __ LoadUniqueObject(R5, ic_data, PP);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
+ __ LoadUniqueObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
@@ -1264,26 +1265,25 @@
intptr_t token_pos,
LocationSummary* locs) {
MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
- const String& name = String::Handle(ic_data.target_name());
+ const String& name = String::Handle(zone(), ic_data.target_name());
const Array& arguments_descriptor =
- Array::ZoneHandle(ic_data.arguments_descriptor());
+ Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache =
- MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
+ const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
+ zone(), table->Lookup(name, arguments_descriptor));
const Register receiverR = R0;
const Register cacheR = R1;
const Register targetR = R1;
- __ LoadFromOffset(receiverR, SP, (argument_count - 1) * kWordSize, PP);
- __ LoadObject(cacheR, cache, PP);
+ __ LoadFromOffset(receiverR, SP, (argument_count - 1) * kWordSize);
+ __ LoadObject(cacheR, cache);
if (FLAG_use_megamorphic_stub) {
- StubCode* stub_code = isolate()->stub_code();
- __ BranchLink(&stub_code->MegamorphicLookupLabel(), PP);
+ __ BranchLink(*StubCode::MegamorphicLookup_entry());
} else {
StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR);
}
- __ LoadObject(R5, ic_data, PP);
- __ LoadObject(R4, arguments_descriptor, PP);
+ __ LoadObject(R5, ic_data);
+ __ LoadObject(R4, arguments_descriptor);
__ blr(targetR);
AddCurrentDescriptor(RawPcDescriptors::kOther,
Isolate::kNoDeoptId, token_pos);
@@ -1306,14 +1306,12 @@
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- StubCode* stub_code = isolate()->stub_code();
- const uword label_address =
- stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
- ExternalLabel target_label(label_address);
- __ LoadObject(R5, ic_data, PP);
+ const StubEntry* stub_entry =
+ StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
+ __ LoadObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- &target_label,
+ *stub_entry,
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
@@ -1327,13 +1325,12 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- StubCode* stub_code = isolate()->stub_code();
- __ LoadObject(R4, arguments_descriptor, PP);
+ __ LoadObject(R4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_pos,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
AddStaticCallTarget(function);
@@ -1347,16 +1344,15 @@
bool needs_number_check,
intptr_t token_pos) {
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint());
__ Push(reg);
- __ PushObject(obj, PP);
+ __ PushObject(obj);
if (is_optimizing()) {
__ BranchLinkPatchable(
- &stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
__ BranchLinkPatchable(
- &stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1367,7 +1363,7 @@
__ Drop(1); // Discard constant.
__ Pop(reg); // Restore 'reg'.
} else {
- __ CompareObject(reg, obj, PP);
+ __ CompareObject(reg, obj);
}
return EQ;
}
@@ -1378,15 +1374,14 @@
bool needs_number_check,
intptr_t token_pos) {
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ Push(left);
__ Push(right);
if (is_optimizing()) {
__ BranchLinkPatchable(
- &stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
__ BranchLinkPatchable(
- &stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1487,13 +1482,12 @@
__ Comment("EmitTestAndCall");
const Array& arguments_descriptor =
- Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
- argument_names));
- StubCode* stub_code = isolate()->stub_code();
+ Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count,
+ argument_names));
// Load receiver into R0.
- __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize, PP);
- __ LoadObject(R4, arguments_descriptor, PP);
+ __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
+ __ LoadObject(R4, arguments_descriptor);
const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid;
const intptr_t kNumChecks = ic_data.NumberOfChecks();
@@ -1513,10 +1507,10 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
- const Function& function = Function::Handle(ic_data.GetTargetAt(0));
+ const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0));
AddStaticCallTarget(function);
__ Drop(argument_count);
if (kNumChecks > 1) {
@@ -1539,12 +1533,12 @@
// will fail if there was only one check and receiver is not Smi.
if (kSortedLen == 0) return;
- __ LoadClassId(R2, R0, PP);
+ __ LoadClassId(R2, R0);
for (intptr_t i = 0; i < kSortedLen; i++) {
const bool kIsLastCheck = (i == (kSortedLen - 1));
ASSERT(sorted[i].cid != kSmiCid);
Label next_test;
- __ CompareImmediate(R2, sorted[i].cid, PP);
+ __ CompareImmediate(R2, sorted[i].cid);
if (kIsLastCheck) {
__ b(failed, NE);
} else {
@@ -1554,7 +1548,7 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
const Function& function = *sorted[i].target;
@@ -1583,20 +1577,20 @@
} else {
ASSERT(destination.IsStackSlot());
const intptr_t dest_offset = destination.ToStackSlotOffset();
- __ StoreToOffset(source.reg(), destination.base_reg(), dest_offset, PP);
+ __ StoreToOffset(source.reg(), destination.base_reg(), dest_offset);
}
} else if (source.IsStackSlot()) {
if (destination.IsRegister()) {
const intptr_t source_offset = source.ToStackSlotOffset();
__ LoadFromOffset(
- destination.reg(), source.base_reg(), source_offset, PP);
+ destination.reg(), source.base_reg(), source_offset);
} else {
ASSERT(destination.IsStackSlot());
const intptr_t source_offset = source.ToStackSlotOffset();
const intptr_t dest_offset = destination.ToStackSlotOffset();
ScratchRegisterScope tmp(this, kNoRegister);
- __ LoadFromOffset(tmp.reg(), source.base_reg(), source_offset, PP);
- __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset, PP);
+ __ LoadFromOffset(tmp.reg(), source.base_reg(), source_offset);
+ __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset);
}
} else if (source.IsFpuRegister()) {
if (destination.IsFpuRegister()) {
@@ -1605,37 +1599,37 @@
if (destination.IsDoubleStackSlot()) {
const intptr_t dest_offset = destination.ToStackSlotOffset();
VRegister src = source.fpu_reg();
- __ StoreDToOffset(src, destination.base_reg(), dest_offset, PP);
+ __ StoreDToOffset(src, destination.base_reg(), dest_offset);
} else {
ASSERT(destination.IsQuadStackSlot());
const intptr_t dest_offset = destination.ToStackSlotOffset();
__ StoreQToOffset(
- source.fpu_reg(), destination.base_reg(), dest_offset, PP);
+ source.fpu_reg(), destination.base_reg(), dest_offset);
}
}
} else if (source.IsDoubleStackSlot()) {
if (destination.IsFpuRegister()) {
const intptr_t source_offset = source.ToStackSlotOffset();
const VRegister dst = destination.fpu_reg();
- __ LoadDFromOffset(dst, source.base_reg(), source_offset, PP);
+ __ LoadDFromOffset(dst, source.base_reg(), source_offset);
} else {
ASSERT(destination.IsDoubleStackSlot());
const intptr_t source_offset = source.ToStackSlotOffset();
const intptr_t dest_offset = destination.ToStackSlotOffset();
- __ LoadDFromOffset(VTMP, source.base_reg(), source_offset, PP);
- __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset, PP);
+ __ LoadDFromOffset(VTMP, source.base_reg(), source_offset);
+ __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset);
}
} else if (source.IsQuadStackSlot()) {
if (destination.IsFpuRegister()) {
const intptr_t source_offset = source.ToStackSlotOffset();
__ LoadQFromOffset(
- destination.fpu_reg(), source.base_reg(), source_offset, PP);
+ destination.fpu_reg(), source.base_reg(), source_offset);
} else {
ASSERT(destination.IsQuadStackSlot());
const intptr_t source_offset = source.ToStackSlotOffset();
const intptr_t dest_offset = destination.ToStackSlotOffset();
- __ LoadQFromOffset(VTMP, source.base_reg(), source_offset, PP);
- __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset, PP);
+ __ LoadQFromOffset(VTMP, source.base_reg(), source_offset);
+ __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset);
}
} else {
ASSERT(source.IsConstant());
@@ -1644,10 +1638,9 @@
if (constant.IsSmi() &&
(source.constant_instruction()->representation() == kUnboxedInt32)) {
__ LoadImmediate(destination.reg(),
- static_cast<int32_t>(Smi::Cast(constant).Value()),
- PP);
+ static_cast<int32_t>(Smi::Cast(constant).Value()));
} else {
- __ LoadObject(destination.reg(), constant, PP);
+ __ LoadObject(destination.reg(), constant);
}
} else if (destination.IsFpuRegister()) {
const VRegister dst = destination.fpu_reg();
@@ -1655,19 +1648,19 @@
__ veor(dst, dst, dst);
} else {
ScratchRegisterScope tmp(this, kNoRegister);
- __ LoadObject(tmp.reg(), constant, PP);
- __ LoadDFieldFromOffset(dst, tmp.reg(), Double::value_offset(), PP);
+ __ LoadObject(tmp.reg(), constant);
+ __ LoadDFieldFromOffset(dst, tmp.reg(), Double::value_offset());
}
} else if (destination.IsDoubleStackSlot()) {
if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) {
__ veor(VTMP, VTMP, VTMP);
} else {
ScratchRegisterScope tmp(this, kNoRegister);
- __ LoadObject(tmp.reg(), constant, PP);
- __ LoadDFieldFromOffset(VTMP, tmp.reg(), Double::value_offset(), PP);
+ __ LoadObject(tmp.reg(), constant);
+ __ LoadDFieldFromOffset(VTMP, tmp.reg(), Double::value_offset());
}
const intptr_t dest_offset = destination.ToStackSlotOffset();
- __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset, PP);
+ __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset);
} else {
ASSERT(destination.IsStackSlot());
const intptr_t dest_offset = destination.ToStackSlotOffset();
@@ -1675,12 +1668,11 @@
if (constant.IsSmi() &&
(source.constant_instruction()->representation() == kUnboxedInt32)) {
__ LoadImmediate(tmp.reg(),
- static_cast<int32_t>(Smi::Cast(constant).Value()),
- PP);
+ static_cast<int32_t>(Smi::Cast(constant).Value()));
} else {
- __ LoadObject(tmp.reg(), constant, PP);
+ __ LoadObject(tmp.reg(), constant);
}
- __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset, PP);
+ __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset);
}
}
@@ -1731,12 +1723,12 @@
: source.ToStackSlotOffset();
if (double_width) {
- __ LoadDFromOffset(VTMP, base_reg, slot_offset, PP);
- __ StoreDToOffset(reg, base_reg, slot_offset, PP);
+ __ LoadDFromOffset(VTMP, base_reg, slot_offset);
+ __ StoreDToOffset(reg, base_reg, slot_offset);
__ fmovdd(reg, VTMP);
} else {
- __ LoadQFromOffset(VTMP, base_reg, slot_offset, PP);
- __ StoreQToOffset(reg, base_reg, slot_offset, PP);
+ __ LoadQFromOffset(VTMP, base_reg, slot_offset);
+ __ StoreQToOffset(reg, base_reg, slot_offset);
__ vmov(reg, VTMP);
}
} else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
@@ -1745,20 +1737,20 @@
ScratchFpuRegisterScope ensure_scratch(this, kNoFpuRegister);
VRegister scratch = ensure_scratch.reg();
- __ LoadDFromOffset(VTMP, source.base_reg(), source_offset, PP);
- __ LoadDFromOffset(scratch, destination.base_reg(), dest_offset, PP);
- __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset, PP);
- __ StoreDToOffset(scratch, source.base_reg(), source_offset, PP);
+ __ LoadDFromOffset(VTMP, source.base_reg(), source_offset);
+ __ LoadDFromOffset(scratch, destination.base_reg(), dest_offset);
+ __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset);
+ __ StoreDToOffset(scratch, source.base_reg(), source_offset);
} else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) {
const intptr_t source_offset = source.ToStackSlotOffset();
const intptr_t dest_offset = destination.ToStackSlotOffset();
ScratchFpuRegisterScope ensure_scratch(this, kNoFpuRegister);
VRegister scratch = ensure_scratch.reg();
- __ LoadQFromOffset(VTMP, source.base_reg(), source_offset, PP);
- __ LoadQFromOffset(scratch, destination.base_reg(), dest_offset, PP);
- __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset, PP);
- __ StoreQToOffset(scratch, source.base_reg(), source_offset, PP);
+ __ LoadQFromOffset(VTMP, source.base_reg(), source_offset);
+ __ LoadQFromOffset(scratch, destination.base_reg(), dest_offset);
+ __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset);
+ __ StoreQToOffset(scratch, source.base_reg(), source_offset);
} else {
UNREACHABLE();
}
@@ -1811,8 +1803,8 @@
intptr_t stack_offset) {
ScratchRegisterScope tmp(this, reg);
__ mov(tmp.reg(), reg);
- __ LoadFromOffset(reg, base_reg, stack_offset, PP);
- __ StoreToOffset(tmp.reg(), base_reg, stack_offset, PP);
+ __ LoadFromOffset(reg, base_reg, stack_offset);
+ __ StoreToOffset(tmp.reg(), base_reg, stack_offset);
}
@@ -1822,10 +1814,10 @@
intptr_t stack_offset2) {
ScratchRegisterScope tmp1(this, kNoRegister);
ScratchRegisterScope tmp2(this, tmp1.reg());
- __ LoadFromOffset(tmp1.reg(), base_reg1, stack_offset1, PP);
- __ LoadFromOffset(tmp2.reg(), base_reg2, stack_offset2, PP);
- __ StoreToOffset(tmp1.reg(), base_reg2, stack_offset2, PP);
- __ StoreToOffset(tmp2.reg(), base_reg1, stack_offset1, PP);
+ __ LoadFromOffset(tmp1.reg(), base_reg1, stack_offset1);
+ __ LoadFromOffset(tmp2.reg(), base_reg2, stack_offset2);
+ __ StoreToOffset(tmp1.reg(), base_reg2, stack_offset2);
+ __ StoreToOffset(tmp2.reg(), base_reg1, stack_offset1);
}
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 46ce12d..388b6d1 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -100,12 +100,14 @@
// The real frame starts here.
builder->MarkFrameStart();
+ Zone* zone = compiler->zone();
+
// Callee's PC marker is not used anymore. Pass Code::null() to set to 0.
- builder->AddPcMarker(Function::Handle(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone), slot_ix++);
// Current FP and PC.
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(Function::Handle(current->code().function()),
+ builder->AddReturnAddress(Function::Handle(zone, current->code().function()),
deopt_id(),
slot_ix++);
@@ -122,7 +124,8 @@
}
// Current PC marker and caller FP.
- builder->AddPcMarker(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(
+ zone, current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
Environment* previous = current;
@@ -130,9 +133,10 @@
while (current != NULL) {
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(Function::Handle(current->code().function()),
- Isolate::ToDeoptAfter(current->deopt_id()),
- slot_ix++);
+ builder->AddReturnAddress(
+ Function::Handle(zone, current->code().function()),
+ Isolate::ToDeoptAfter(current->deopt_id()),
+ slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
// we must read them from the previous environment.
@@ -152,7 +156,7 @@
}
// PC marker and caller FP.
- builder->AddPcMarker(Function::Handle(current->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, current->code().function()),
slot_ix++);
builder->AddCallerFp(slot_ix++);
@@ -189,8 +193,7 @@
ASSERT(deopt_env() != NULL);
- StubCode* stub_code = compiler->isolate()->stub_code();
- __ call(&stub_code->DeoptimizeLabel());
+ __ Call(*StubCode::Deoptimize_entry());
set_pc_offset(assem->CodeSize());
__ int3();
#undef __
@@ -225,24 +228,23 @@
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
+ SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
- StubCode* stub_code = isolate()->stub_code();
__ LoadObject(temp_reg, type_test_cache);
__ pushl(temp_reg); // Subtype test cache.
__ pushl(instance_reg); // Instance.
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
__ pushl(raw_null);
- __ call(&stub_code->Subtype1TestCacheLabel());
+ __ Call(*StubCode::Subtype1TestCache_entry());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
__ pushl(raw_null);
- __ call(&stub_code->Subtype2TestCacheLabel());
+ __ Call(*StubCode::Subtype2TestCache_entry());
} else if (test_kind == kTestTypeThreeArgs) {
__ pushl(type_arguments_reg);
- __ call(&stub_code->Subtype3TestCacheLabel());
+ __ Call(*StubCode::Subtype3TestCache_entry());
} else {
UNREACHABLE();
}
@@ -270,11 +272,11 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
const Register kInstanceReg = EAX;
- Error& malformed_error = Error::Handle();
- const Type& int_type = Type::Handle(Type::IntType());
+ Error& malformed_error = Error::Handle(zone());
+ const Type& int_type = Type::Handle(zone(), Type::IntType());
const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error);
// Malformed type should have been handled at graph construction time.
ASSERT(smi_is_ok || malformed_error.IsNull());
@@ -288,7 +290,7 @@
const intptr_t num_type_params = type_class.NumTypeParameters();
const intptr_t from_index = num_type_args - num_type_params;
const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(type.arguments());
+ TypeArguments::ZoneHandle(zone(), type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(from_index, num_type_params);
// Signature class is an instantiated parameterized type.
@@ -309,12 +311,12 @@
// If one type argument only, check if type argument is Object or dynamic.
if (type_arguments.Length() == 1) {
const AbstractType& tp_argument = AbstractType::ZoneHandle(
- type_arguments.TypeAt(0));
+ zone(), type_arguments.TypeAt(0));
ASSERT(!tp_argument.IsMalformed());
if (tp_argument.IsType()) {
ASSERT(tp_argument.HasResolvedTypeClass());
// Check if type argument is dynamic or Object.
- const Type& object_type = Type::Handle(Type::ObjectType());
+ const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(tp_argument, NULL)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@@ -359,16 +361,16 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::Handle(type.type_class());
+ const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
const Register kInstanceReg = EAX;
__ testl(kInstanceReg, Immediate(kSmiTagMask));
// If instance is Smi, check directly.
- const Class& smi_class = Class::Handle(Smi::Class());
- if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ const Class& smi_class = Class::Handle(zone(), Smi::Class());
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()),
type_class,
- TypeArguments::Handle(),
+ TypeArguments::Handle(zone()),
NULL)) {
__ j(ZERO, is_instance_lbl);
} else {
@@ -399,7 +401,7 @@
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
- if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
+ if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) {
GenerateNumberTypeCheck(
kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
return false;
@@ -471,18 +473,18 @@
FieldAddress(EDX, TypeArguments::type_at_offset(type_param.index())));
// EDI: concrete type of type.
// Check if type argument is dynamic.
- __ CompareObject(EDI, Type::ZoneHandle(Type::DynamicType()));
+ __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::DynamicType()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(EDI, Type::ZoneHandle(Type::ObjectType()));
+ __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType()));
__ j(EQUAL, is_instance_lbl);
// For Smi check quickly against int and num interfaces.
Label not_smi;
__ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi?
__ j(NOT_ZERO, ¬_smi, Assembler::kNearJump);
- __ CompareObject(EDI, Type::ZoneHandle(Type::IntType()));
+ __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(EDI, Type::ZoneHandle(Type::Number()));
+ __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number()));
__ j(EQUAL, is_instance_lbl);
// Smi must be handled in runtime.
Label fall_through;
@@ -495,7 +497,7 @@
const Register kTypeArgumentsReg = EDX;
const Register kTempReg = EDI;
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(
+ SubtypeTestCache::ZoneHandle(zone(),
GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
kInstanceReg,
kTypeArgumentsReg,
@@ -546,7 +548,7 @@
return SubtypeTestCache::null();
}
if (type.IsInstantiated()) {
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
// A class equality check is only applicable with a dst type of a
// non-parameterized class, non-signature class, or with a raw dst type of
// a parameterized class.
@@ -617,7 +619,7 @@
}
// Generate inline instanceof test.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, type,
&is_instance, &is_not_instance);
@@ -718,7 +720,7 @@
}
// Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, dst_type,
&is_assignable, &runtime_call);
@@ -882,7 +884,7 @@
__ jmp(&assign_optional_parameter, Assembler::kNearJump);
__ Bind(&load_default_value);
// Load EAX with default argument.
- const Object& value = Object::ZoneHandle(
+ const Object& value = Object::ZoneHandle(zone(),
parsed_function().default_parameter_values().At(
param_pos - num_fixed_params));
__ LoadObject(EAX, value);
@@ -917,7 +919,7 @@
__ cmpl(ECX, Immediate(param_pos));
__ j(GREATER, &next_parameter, Assembler::kNearJump);
// Load EAX with default argument.
- const Object& value = Object::ZoneHandle(
+ const Object& value = Object::ZoneHandle(zone(),
parsed_function().default_parameter_values().At(i));
__ LoadObject(EAX, value);
// Assign EAX to fp[kFirstLocalSlotFromFp - param_pos].
@@ -941,7 +943,7 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
__ LeaveFrame(); // The arguments are still on the stack.
- __ jmp(&isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ __ Jmp(*StubCode::CallClosureNoSuchMethod_entry());
// The noSuchMethod call may return to the caller, but not here.
} else if (check_correct_named_args) {
__ Stop("Wrong arguments");
@@ -1003,7 +1005,6 @@
if (CanOptimizeFunction() &&
function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
- StubCode* stub_code = isolate()->stub_code();
const Register function_reg = EDI;
__ LoadObject(function_reg, function);
@@ -1018,7 +1019,7 @@
__ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()),
Immediate(GetOptimizationThreshold()));
ASSERT(function_reg == EDI);
- __ j(GREATER_EQUAL, &stub_code->OptimizeFunctionLabel());
+ __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry());
} else if (!flow_graph().IsCompiledForOsr()) {
entry_patch_pc_offset_ = assembler()->CodeSize();
}
@@ -1048,7 +1049,6 @@
const int num_fixed_params = function.num_fixed_parameters();
const int num_copied_params = parsed_function().num_copied_params();
const int num_locals = parsed_function().num_stack_locals();
- StubCode* stub_code = isolate()->stub_code();
// We check the number of passed arguments when we have to copy them due to
// the presence of optional parameters.
@@ -1077,7 +1077,7 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
__ LeaveFrame(); // The arguments are still on the stack.
- __ jmp(&stub_code->CallClosureNoSuchMethodLabel());
+ __ Jmp(*StubCode::CallClosureNoSuchMethod_entry());
// The noSuchMethod call may return to the caller, but not here.
} else {
__ Stop("Wrong number of arguments");
@@ -1145,20 +1145,20 @@
// Emit function patching code. This will be swapped with the first 5 bytes
// at entry point.
patch_code_pc_offset_ = assembler()->CodeSize();
- __ jmp(&stub_code->FixCallersTargetLabel());
+ __ Jmp(*StubCode::FixCallersTarget_entry());
if (is_optimizing()) {
lazy_deopt_pc_offset_ = assembler()->CodeSize();
- __ jmp(&stub_code->DeoptimizeLazyLabel());
+ __ Jmp(*StubCode::DeoptimizeLazy_entry());
}
}
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ call(label);
+ __ Call(stub_entry);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}
@@ -1166,10 +1166,10 @@
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ call(label);
+ __ Call(stub_entry);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
// Marks either the continuation point in unoptimized code or the
@@ -1214,14 +1214,12 @@
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- StubCode* stub_code = isolate()->stub_code();
- const uword label_address =
- stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
- ExternalLabel target_label(label_address);
+ const StubEntry& stub_entry =
+ *StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(ECX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- &target_label,
+ stub_entry,
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
@@ -1234,8 +1232,8 @@
// overflow; and though we do not reset the counters when we optimize or
// deoptimize, there is a bound on the number of
// optimization/deoptimization cycles we will attempt.
- const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
- counter.SetAt(0, Smi::Handle(Smi::New(0)));
+ const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld));
+ counter.SetAt(0, Smi::Handle(zone(), Smi::New(0)));
__ Comment("Edge counter");
__ LoadObject(EAX, counter);
intptr_t increment_start = assembler_->CodeSize();
@@ -1257,7 +1255,7 @@
void FlowGraphCompiler::EmitOptimizedInstanceCall(
- ExternalLabel* target_label,
+ const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
@@ -1274,14 +1272,14 @@
__ LoadObject(ECX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
}
-void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
+void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
@@ -1291,7 +1289,7 @@
__ LoadObject(ECX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
@@ -1305,12 +1303,12 @@
intptr_t token_pos,
LocationSummary* locs) {
MegamorphicCacheTable* table = isolate()->megamorphic_cache_table();
- const String& name = String::Handle(ic_data.target_name());
+ const String& name = String::Handle(zone(), ic_data.target_name());
const Array& arguments_descriptor =
- Array::ZoneHandle(ic_data.arguments_descriptor());
+ Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache =
- MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
+ const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
+ table->Lookup(name, arguments_descriptor));
const Register receiverR = EDI;
const Register cacheR = EBX;
const Register targetR = EBX;
@@ -1318,8 +1316,7 @@
__ LoadObject(cacheR, cache);
if (FLAG_use_megamorphic_stub) {
- StubCode* stub_code = isolate()->stub_code();
- __ call(&stub_code->MegamorphicLookupLabel());
+ __ Call(*StubCode::MegamorphicLookup_entry());
} else {
StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR);
}
@@ -1349,13 +1346,12 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- StubCode* stub_code = isolate()->stub_code();
__ LoadObject(EDX, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_pos,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
AddStaticCallTarget(function);
@@ -1378,13 +1374,12 @@
}
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ pushl(reg);
__ PushObject(obj);
if (is_optimizing()) {
- __ call(&stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
- __ call(&stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1406,13 +1401,12 @@
bool needs_number_check,
intptr_t token_pos) {
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ pushl(left);
__ pushl(right);
if (is_optimizing()) {
- __ call(&stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
- __ call(&stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1519,9 +1513,8 @@
ASSERT(is_optimizing());
__ Comment("EmitTestAndCall");
const Array& arguments_descriptor =
- Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
- argument_names));
- StubCode* stub_code = isolate()->stub_code();
+ Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count,
+ argument_names));
// Load receiver into EAX.
__ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize));
__ LoadObject(EDX, arguments_descriptor);
@@ -1544,10 +1537,10 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
- const Function& function = Function::Handle(ic_data.GetTargetAt(0));
+ const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0));
AddStaticCallTarget(function);
__ Drop(argument_count);
if (kNumChecks > 1) {
@@ -1586,7 +1579,7 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
const Function& function = *sorted[i].target;
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index b65b62e..a717323 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -62,14 +62,14 @@
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
- assembler()->set_allow_constant_pool(false);
+ assembler()->set_constant_pool_allowed(false);
}
void FlowGraphCompiler::ExitIntrinsicMode() {
ASSERT(intrinsic_mode());
intrinsic_mode_ = false;
- assembler()->set_allow_constant_pool(true);
+ assembler()->set_constant_pool_allowed(true);
}
@@ -94,15 +94,17 @@
// The real frame starts here.
builder->MarkFrameStart();
+ Zone* zone = compiler->zone();
+
// Current PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(Function::Handle(current->code().function()),
+ builder->AddReturnAddress(Function::Handle(zone, current->code().function()),
deopt_id(),
slot_ix++);
// Callee's PC marker is not used anymore. Pass Code::null() to set to 0.
- builder->AddPcMarker(Function::Handle(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone), slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -120,17 +122,19 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPp(
+ Function::Handle(zone, current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(Function::Handle(current->code().function()),
- Isolate::ToDeoptAfter(current->deopt_id()),
- slot_ix++);
+ builder->AddReturnAddress(
+ Function::Handle(zone, current->code().function()),
+ Isolate::ToDeoptAfter(current->deopt_id()),
+ slot_ix++);
// PC marker.
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
@@ -163,7 +167,7 @@
builder->AddCallerPc(slot_ix++);
// PC marker.
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
// For the outermost environment, set the incoming arguments.
@@ -189,8 +193,7 @@
ASSERT(deopt_env() != NULL);
- StubCode* stub_code = compiler->isolate()->stub_code();
- __ BranchLink(&stub_code->DeoptimizeLabel());
+ __ BranchLink(*StubCode::Deoptimize_entry());
set_pc_offset(assem->CodeSize());
#undef __
}
@@ -225,20 +228,19 @@
ASSERT(instance_reg == A0);
ASSERT(temp_reg == kNoRegister); // Unused on MIPS.
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- StubCode* stub_code = isolate()->stub_code();
+ SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
__ LoadUniqueObject(A2, type_test_cache);
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
__ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
- __ BranchLink(&stub_code->Subtype1TestCacheLabel());
+ __ BranchLink(*StubCode::Subtype1TestCache_entry());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
__ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
- __ BranchLink(&stub_code->Subtype2TestCacheLabel());
+ __ BranchLink(*StubCode::Subtype2TestCache_entry());
} else if (test_kind == kTestTypeThreeArgs) {
ASSERT(type_arguments_reg == A1);
- __ BranchLink(&stub_code->Subtype3TestCacheLabel());
+ __ BranchLink(*StubCode::Subtype3TestCache_entry());
} else {
UNREACHABLE();
}
@@ -261,11 +263,11 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
const Register kInstanceReg = A0;
- Error& malformed_error = Error::Handle();
- const Type& int_type = Type::Handle(Type::IntType());
+ Error& malformed_error = Error::Handle(zone());
+ const Type& int_type = Type::Handle(zone(), Type::IntType());
const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error);
// Malformed type should have been handled at graph construction time.
ASSERT(smi_is_ok || malformed_error.IsNull());
@@ -279,7 +281,7 @@
const intptr_t num_type_params = type_class.NumTypeParameters();
const intptr_t from_index = num_type_args - num_type_params;
const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(type.arguments());
+ TypeArguments::ZoneHandle(zone(), type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(from_index, num_type_params);
// Signature class is an instantiated parameterized type.
@@ -298,13 +300,13 @@
}
// If one type argument only, check if type argument is Object or dynamic.
if (type_arguments.Length() == 1) {
- const AbstractType& tp_argument = AbstractType::ZoneHandle(
+ const AbstractType& tp_argument = AbstractType::ZoneHandle(zone(),
type_arguments.TypeAt(0));
ASSERT(!tp_argument.IsMalformed());
if (tp_argument.IsType()) {
ASSERT(tp_argument.HasResolvedTypeClass());
// Check if type argument is dynamic or Object.
- const Type& object_type = Type::Handle(Type::ObjectType());
+ const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(tp_argument, NULL)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@@ -350,16 +352,16 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::Handle(type.type_class());
+ const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
const Register kInstanceReg = A0;
__ andi(T0, A0, Immediate(kSmiTagMask));
// If instance is Smi, check directly.
- const Class& smi_class = Class::Handle(Smi::Class());
- if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ const Class& smi_class = Class::Handle(zone(), Smi::Class());
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()),
type_class,
- TypeArguments::Handle(),
+ TypeArguments::Handle(zone()),
NULL)) {
__ beq(T0, ZR, is_instance_lbl);
} else {
@@ -386,7 +388,7 @@
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
- if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
+ if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) {
GenerateNumberTypeCheck(
kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
return false;
@@ -454,15 +456,19 @@
FieldAddress(A1, TypeArguments::type_at_offset(type_param.index())));
// R2: concrete type of type.
// Check if type argument is dynamic.
- __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl);
- __ BranchEqual(T2, Type::ZoneHandle(Type::ObjectType()), is_instance_lbl);
+ __ BranchEqual(T2,
+ Type::ZoneHandle(zone(), Type::DynamicType()), is_instance_lbl);
+ __ BranchEqual(T2,
+ Type::ZoneHandle(zone(), Type::ObjectType()), is_instance_lbl);
// For Smi check quickly against int and num interfaces.
Label not_smi;
__ andi(CMPRES1, A0, Immediate(kSmiTagMask));
__ bne(CMPRES1, ZR, ¬_smi); // Value is Smi?
- __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl);
- __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl);
+ __ BranchEqual(T2,
+ Type::ZoneHandle(zone(), Type::IntType()), is_instance_lbl);
+ __ BranchEqual(T2,
+ Type::ZoneHandle(zone(), Type::Number()), is_instance_lbl);
// Smi must be handled in runtime.
Label fall_through;
__ b(&fall_through);
@@ -474,7 +480,7 @@
const Register kTypeArgumentsReg = A1;
const Register kTempReg = kNoRegister;
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(
+ SubtypeTestCache::ZoneHandle(zone(),
GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
kInstanceReg,
kTypeArgumentsReg,
@@ -525,7 +531,7 @@
return SubtypeTestCache::null();
}
if (type.IsInstantiated()) {
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
// A class equality check is only applicable with a dst type of a
// non-parameterized class, non-signature class, or with a raw dst type of
// a parameterized class.
@@ -596,7 +602,7 @@
}
// Generate inline instanceof test.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, type,
&is_instance, &is_not_instance);
@@ -707,7 +713,7 @@
}
// Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, dst_type,
&is_assignable, &runtime_call);
@@ -874,7 +880,7 @@
__ Bind(&load_default_value);
// Load T3 with default argument.
- const Object& value = Object::ZoneHandle(
+ const Object& value = Object::ZoneHandle(zone(),
parsed_function().default_parameter_values().At(
param_pos - num_fixed_params));
__ LoadObject(T3, value);
@@ -908,7 +914,7 @@
const int param_pos = num_fixed_params + i;
__ BranchSignedGreater(T2, Immediate(param_pos), &next_parameter);
// Load T3 with default argument.
- const Object& value = Object::ZoneHandle(
+ const Object& value = Object::ZoneHandle(zone(),
parsed_function().default_parameter_values().At(i));
__ LoadObject(T3, value);
// Assign T3 to fp[kFirstLocalSlotFromFp - param_pos].
@@ -930,7 +936,7 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ Branch(&isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
// The noSuchMethod call may return to the caller, but not here.
} else if (check_correct_named_args) {
__ Stop("Wrong arguments");
@@ -993,7 +999,6 @@
function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = T0;
- StubCode* stub_code = isolate()->stub_code();
__ GetNextPC(T2, TMP);
@@ -1028,7 +1033,7 @@
T1, Immediate(GetOptimizationThreshold()), &dont_branch);
ASSERT(function_reg == T0);
- __ Branch(&stub_code->OptimizeFunctionLabel());
+ __ Branch(*StubCode::OptimizeFunction_entry());
__ Bind(&dont_branch);
@@ -1068,7 +1073,6 @@
const int num_fixed_params = function.num_fixed_parameters();
const int num_copied_params = parsed_function().num_copied_params();
const int num_locals = parsed_function().num_stack_locals();
- StubCode* stub_code = isolate()->stub_code();
// We check the number of passed arguments when we have to copy them due to
// the presence of optional parameters.
@@ -1096,7 +1100,7 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ Branch(&isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
// The noSuchMethod call may return to the caller, but not here.
} else {
__ Stop("Wrong number of arguments");
@@ -1151,20 +1155,20 @@
// Emit function patching code. This will be swapped with the first 5 bytes
// at entry point.
patch_code_pc_offset_ = assembler()->CodeSize();
- __ BranchPatchable(&stub_code->FixCallersTargetLabel());
+ __ BranchPatchable(*StubCode::FixCallersTarget_entry());
if (is_optimizing()) {
lazy_deopt_pc_offset_ = assembler()->CodeSize();
- __ Branch(&stub_code->DeoptimizeLazyLabel());
+ __ Branch(*StubCode::DeoptimizeLazy_entry());
}
}
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(label);
+ __ BranchLinkPatchable(stub_entry);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}
@@ -1172,10 +1176,10 @@
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(label);
+ __ BranchLinkPatchable(stub_entry);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
// Marks either the continuation point in unoptimized code or the
@@ -1224,8 +1228,8 @@
// overflow; and though we do not reset the counters when we optimize or
// deoptimize, there is a bound on the number of
// optimization/deoptimization cycles we will attempt.
- const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
- counter.SetAt(0, Smi::Handle(Smi::New(0)));
+ const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld));
+ counter.SetAt(0, Smi::Handle(zone(), Smi::New(0)));
__ Comment("Edge counter");
__ LoadUniqueObject(T0, counter);
__ lw(T1, FieldAddress(T0, Array::element_offset(0)));
@@ -1235,13 +1239,13 @@
void FlowGraphCompiler::EmitOptimizedInstanceCall(
- ExternalLabel* target_label,
+ const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
// to inlining in optimized code, that function may not correspond to the
@@ -1253,25 +1257,25 @@
__ LoadUniqueObject(S5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
}
-void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
+void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
__ Comment("InstanceCall");
__ LoadUniqueObject(S5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Comment("InstanceCall return");
@@ -1286,12 +1290,12 @@
intptr_t token_pos,
LocationSummary* locs) {
MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
- const String& name = String::Handle(ic_data.target_name());
+ const String& name = String::Handle(zone(), ic_data.target_name());
const Array& arguments_descriptor =
- Array::ZoneHandle(ic_data.arguments_descriptor());
+ Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache =
- MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
+ const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
+ zone(), table->Lookup(name, arguments_descriptor));
__ Comment("MegamorphicInstanceCall");
const Register receiverR = T0;
const Register cacheR = T1;
@@ -1300,8 +1304,7 @@
__ LoadObject(cacheR, cache);
if (FLAG_use_megamorphic_stub) {
- StubCode* stub_code = isolate()->stub_code();
- __ BranchLink(&stub_code->MegamorphicLookupLabel());
+ __ BranchLink(*StubCode::MegamorphicLookup_entry());
} else {
StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR);
}
@@ -1329,14 +1332,12 @@
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- StubCode* stub_code = isolate()->stub_code();
- const uword label_address =
- stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
- ExternalLabel target_label(label_address);
+ const StubEntry* stub_entry =
+ StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(S5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- &target_label,
+ *stub_entry,
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
@@ -1350,14 +1351,13 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- StubCode* stub_code = isolate()->stub_code();
__ Comment("StaticCall");
__ LoadObject(S4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_pos,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
AddStaticCallTarget(function);
@@ -1374,7 +1374,6 @@
ASSERT(!needs_number_check ||
(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()));
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint());
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(reg, Address(SP, 1 * kWordSize));
@@ -1382,10 +1381,10 @@
__ sw(TMP, Address(SP, 0 * kWordSize));
if (is_optimizing()) {
__ BranchLinkPatchable(
- &stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
__ BranchLinkPatchable(
- &stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1411,16 +1410,15 @@
intptr_t token_pos) {
__ Comment("EqualityRegRegCompare");
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(left, Address(SP, 1 * kWordSize));
__ sw(right, Address(SP, 0 * kWordSize));
if (is_optimizing()) {
__ BranchLinkPatchable(
- &stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
__ BranchLinkPatchable(
- &stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1550,9 +1548,8 @@
ASSERT(is_optimizing());
__ Comment("EmitTestAndCall");
const Array& arguments_descriptor =
- Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
- argument_names));
- StubCode* stub_code = isolate()->stub_code();
+ Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count,
+ argument_names));
// Load receiver into T0.
__ LoadFromOffset(T0, SP, (argument_count - 1) * kWordSize);
@@ -1576,10 +1573,10 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
- const Function& function = Function::Handle(ic_data.GetTargetAt(0));
+ const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0));
AddStaticCallTarget(function);
__ Drop(argument_count);
if (kNumChecks > 1) {
@@ -1616,7 +1613,7 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
const Function& function = *sorted[i].target;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 3aa6f29..b28c25a 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -67,14 +67,13 @@
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
- assembler()->set_allow_constant_pool(false);
+ ASSERT(!assembler()->constant_pool_allowed());
}
void FlowGraphCompiler::ExitIntrinsicMode() {
ASSERT(intrinsic_mode());
intrinsic_mode_ = false;
- assembler()->set_allow_constant_pool(true);
}
@@ -99,11 +98,13 @@
// The real frame starts here.
builder->MarkFrameStart();
+ Zone* zone = compiler->zone();
+
// Current PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
- builder->AddPcMarker(Function::Handle(), slot_ix++);
+ builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(Function::Handle(current->code().function()),
+ builder->AddReturnAddress(Function::Handle(zone, current->code().function()),
deopt_id(),
slot_ix++);
@@ -123,16 +124,18 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPp(Function::Handle(zone, current->code().function()),
+ slot_ix++);
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(Function::Handle(current->code().function()),
- Isolate::ToDeoptAfter(current->deopt_id()),
- slot_ix++);
+ builder->AddReturnAddress(
+ Function::Handle(zone, current->code().function()),
+ Isolate::ToDeoptAfter(current->deopt_id()),
+ slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
// we must read them from the previous environment.
@@ -161,7 +164,7 @@
// For the outermost environment, set caller PC, caller PP, and caller FP.
builder->AddCallerPp(slot_ix++);
// PC marker.
- builder->AddPcMarker(Function::Handle(previous->code().function()),
+ builder->AddPcMarker(Function::Handle(zone, previous->code().function()),
slot_ix++);
builder->AddCallerFp(slot_ix++);
builder->AddCallerPc(slot_ix++);
@@ -189,8 +192,7 @@
ASSERT(deopt_env() != NULL);
- StubCode* stub_code = compiler->isolate()->stub_code();
- __ Call(&stub_code->DeoptimizeLabel(), PP);
+ __ Call(*StubCode::Deoptimize_entry());
set_pc_offset(assem->CodeSize());
__ int3();
#undef __
@@ -205,9 +207,9 @@
Label* is_true,
Label* is_false) {
Label fall_through;
- __ CompareObject(bool_register, Object::null_object(), PP);
+ __ CompareObject(bool_register, Object::null_object());
__ j(EQUAL, &fall_through, Assembler::kNearJump);
- __ CompareObject(bool_register, Bool::True(), PP);
+ __ CompareObject(bool_register, Bool::True());
__ j(EQUAL, is_true);
__ jmp(is_false);
__ Bind(&fall_through);
@@ -223,22 +225,21 @@
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- StubCode* stub_code = isolate()->stub_code();
- __ LoadUniqueObject(temp_reg, type_test_cache, PP);
+ SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
+ __ LoadUniqueObject(temp_reg, type_test_cache);
__ pushq(temp_reg); // Subtype test cache.
__ pushq(instance_reg); // Instance.
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
- __ PushObject(Object::null_object(), PP);
- __ Call(&stub_code->Subtype1TestCacheLabel(), PP);
+ __ PushObject(Object::null_object());
+ __ Call(*StubCode::Subtype1TestCache_entry());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
- __ PushObject(Object::null_object(), PP);
- __ Call(&stub_code->Subtype2TestCacheLabel(), PP);
+ __ PushObject(Object::null_object());
+ __ Call(*StubCode::Subtype2TestCache_entry());
} else if (test_kind == kTestTypeThreeArgs) {
__ pushq(type_arguments_reg);
- __ Call(&stub_code->Subtype3TestCacheLabel(), PP);
+ __ Call(*StubCode::Subtype3TestCache_entry());
} else {
UNREACHABLE();
}
@@ -266,11 +267,11 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeWithArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
const Register kInstanceReg = RAX;
- Error& malformed_error = Error::Handle();
- const Type& int_type = Type::Handle(Type::IntType());
+ Error& malformed_error = Error::Handle(zone());
+ const Type& int_type = Type::Handle(zone(), Type::IntType());
const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error);
// Malformed type should have been handled at graph construction time.
ASSERT(smi_is_ok || malformed_error.IsNull());
@@ -284,7 +285,7 @@
const intptr_t num_type_params = type_class.NumTypeParameters();
const intptr_t from_index = num_type_args - num_type_params;
const TypeArguments& type_arguments =
- TypeArguments::ZoneHandle(type.arguments());
+ TypeArguments::ZoneHandle(zone(), type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(from_index, num_type_params);
// Signature class is an instantiated parameterized type.
@@ -304,13 +305,13 @@
}
// If one type argument only, check if type argument is Object or dynamic.
if (type_arguments.Length() == 1) {
- const AbstractType& tp_argument = AbstractType::ZoneHandle(
+ const AbstractType& tp_argument = AbstractType::ZoneHandle(zone(),
type_arguments.TypeAt(0));
ASSERT(!tp_argument.IsMalformed());
if (tp_argument.IsType()) {
ASSERT(tp_argument.HasResolvedTypeClass());
// Check if type argument is dynamic or Object.
- const Type& object_type = Type::Handle(Type::ObjectType());
+ const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(tp_argument, NULL)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@@ -355,16 +356,16 @@
Label* is_not_instance_lbl) {
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::Handle(type.type_class());
+ const Class& type_class = Class::Handle(zone(), type.type_class());
ASSERT(type_class.NumTypeArguments() == 0);
const Register kInstanceReg = RAX;
__ testq(kInstanceReg, Immediate(kSmiTagMask));
// If instance is Smi, check directly.
- const Class& smi_class = Class::Handle(Smi::Class());
- if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
+ const Class& smi_class = Class::Handle(zone(), Smi::Class());
+ if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()),
type_class,
- TypeArguments::Handle(),
+ TypeArguments::Handle(zone()),
NULL)) {
__ j(ZERO, is_instance_lbl);
} else {
@@ -386,14 +387,14 @@
}
if (type.IsFunctionType()) {
// Check if instance is a closure.
- __ LoadClassById(R13, kClassIdReg, PP);
+ __ LoadClassById(R13, kClassIdReg);
__ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
- __ CompareObject(R13, Object::null_object(), PP);
+ __ CompareObject(R13, Object::null_object());
__ j(NOT_EQUAL, is_instance_lbl);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
- if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
+ if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) {
GenerateNumberTypeCheck(
kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
return false;
@@ -421,12 +422,12 @@
Label* is_not_instance_lbl) {
__ Comment("Subtype1TestCacheLookup");
const Register kInstanceReg = RAX;
- __ LoadClass(R10, kInstanceReg, PP);
+ __ LoadClass(R10, kInstanceReg);
// R10: instance class.
// Check immediate superclass equality.
__ movq(R13, FieldAddress(R10, Class::super_type_offset()));
__ movq(R13, FieldAddress(R13, Type::type_class_offset()));
- __ CompareObject(R13, type_class, PP);
+ __ CompareObject(R13, type_class);
__ j(EQUAL, is_instance_lbl);
const Register kTypeArgumentsReg = kNoRegister;
@@ -457,25 +458,25 @@
__ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
// RDX: instantiator type arguments.
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
- __ CompareObject(RDX, Object::null_object(), PP);
+ __ CompareObject(RDX, Object::null_object());
__ j(EQUAL, is_instance_lbl);
__ movq(RDI,
FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index())));
// RDI: Concrete type of type.
// Check if type argument is dynamic.
- __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()), PP);
+ __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::DynamicType()));
__ j(EQUAL, is_instance_lbl);
- const Type& object_type = Type::ZoneHandle(Type::ObjectType());
- __ CompareObject(RDI, object_type, PP);
+ const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType());
+ __ CompareObject(RDI, object_type);
__ j(EQUAL, is_instance_lbl);
// For Smi check quickly against int and num interfaces.
Label not_smi;
__ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
__ j(NOT_ZERO, ¬_smi, Assembler::kNearJump);
- __ CompareObject(RDI, Type::ZoneHandle(Type::IntType()), PP);
+ __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(RDI, Type::ZoneHandle(Type::Number()), PP);
+ __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number()));
__ j(EQUAL, is_instance_lbl);
// Smi must be handled in runtime.
Label fall_through;
@@ -488,7 +489,7 @@
const Register kTypeArgumentsReg = RDX;
const Register kTempReg = R10;
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(
+ SubtypeTestCache::ZoneHandle(zone(),
GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
kInstanceReg,
kTypeArgumentsReg,
@@ -539,7 +540,7 @@
return SubtypeTestCache::null();
}
if (type.IsInstantiated()) {
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
// A class equality check is only applicable with a dst type of a
// non-parameterized class, non-signature class, or with a raw dst type of
// a parameterized class.
@@ -603,12 +604,12 @@
// We can only inline this null check if the type is instantiated at compile
// time, since an uninstantiated type at compile time could be Object or
// dynamic at run time.
- __ CompareObject(RAX, Object::null_object(), PP);
+ __ CompareObject(RAX, Object::null_object());
__ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance);
}
// Generate inline instanceof test.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, type,
&is_instance, &is_not_instance);
@@ -618,12 +619,12 @@
// Generate runtime call.
__ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
__ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ pushq(RAX); // Push the instance.
- __ PushObject(type, PP); // Push the type.
+ __ PushObject(type); // Push the type.
__ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
__ pushq(RDX); // Instantiator type arguments.
- __ LoadUniqueObject(RAX, test_cache, PP);
+ __ LoadUniqueObject(RAX, test_cache);
__ pushq(RAX);
GenerateRuntimeCall(token_pos,
deopt_id,
@@ -635,21 +636,21 @@
__ Drop(5);
if (negate_result) {
__ popq(RDX);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ cmpq(RDX, RAX);
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
} else {
__ popq(RAX);
}
__ jmp(&done, Assembler::kNearJump);
}
__ Bind(&is_not_instance);
- __ LoadObject(RAX, Bool::Get(negate_result), PP);
+ __ LoadObject(RAX, Bool::Get(negate_result));
__ jmp(&done, Assembler::kNearJump);
__ Bind(&is_instance);
- __ LoadObject(RAX, Bool::Get(!negate_result), PP);
+ __ LoadObject(RAX, Bool::Get(!negate_result));
__ Bind(&done);
__ popq(RDX); // Remove pushed instantiator type arguments.
__ popq(RCX); // Remove pushed instantiator.
@@ -683,15 +684,15 @@
__ pushq(RDX); // Store instantiator type arguments.
// A null object is always assignable and is returned as result.
Label is_assignable, runtime_call;
- __ CompareObject(RAX, Object::null_object(), PP);
+ __ CompareObject(RAX, Object::null_object());
__ j(EQUAL, &is_assignable);
// Generate throw new TypeError() if the type is malformed or malbounded.
if (dst_type.IsMalformedOrMalbounded()) {
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ pushq(RAX); // Push the source object.
- __ PushObject(dst_name, PP); // Push the name of the destination.
- __ PushObject(dst_type, PP); // Push the type of the destination.
+ __ PushObject(dst_name); // Push the name of the destination.
+ __ PushObject(dst_type); // Push the type of the destination.
GenerateRuntimeCall(token_pos,
deopt_id,
kBadTypeErrorRuntimeEntry,
@@ -707,20 +708,20 @@
}
// Generate inline type check, linking to runtime call if not assignable.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
test_cache = GenerateInlineInstanceof(token_pos, dst_type,
&is_assignable, &runtime_call);
__ Bind(&runtime_call);
__ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
__ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ pushq(RAX); // Push the source object.
- __ PushObject(dst_type, PP); // Push the type of the destination.
+ __ PushObject(dst_type); // Push the type of the destination.
__ pushq(RCX); // Instantiator.
__ pushq(RDX); // Instantiator type arguments.
- __ PushObject(dst_name, PP); // Push the name of the destination.
- __ LoadUniqueObject(RAX, test_cache, PP);
+ __ PushObject(dst_name); // Push the name of the destination.
+ __ LoadUniqueObject(RAX, test_cache);
__ pushq(RAX);
GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
@@ -772,10 +773,10 @@
FieldAddress(R10, ArgumentsDescriptor::positional_count_offset()));
// Check that min_num_pos_args <= num_pos_args.
Label wrong_num_arguments;
- __ CompareImmediate(RCX, Immediate(Smi::RawValue(min_num_pos_args)), PP);
+ __ CompareImmediate(RCX, Immediate(Smi::RawValue(min_num_pos_args)));
__ j(LESS, &wrong_num_arguments);
// Check that num_pos_args <= max_num_pos_args.
- __ CompareImmediate(RCX, Immediate(Smi::RawValue(max_num_pos_args)), PP);
+ __ CompareImmediate(RCX, Immediate(Smi::RawValue(max_num_pos_args)));
__ j(GREATER, &wrong_num_arguments);
// Copy positional arguments.
@@ -857,7 +858,7 @@
// Load RAX with the name of the argument.
__ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset()));
ASSERT(opt_param[i]->name().IsSymbol());
- __ CompareObject(RAX, opt_param[i]->name(), PP);
+ __ CompareObject(RAX, opt_param[i]->name());
__ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump);
// Load RAX with passed-in argument at provided arg_pos, i.e. at
// fp[kParamEndSlotFromFp + num_args - arg_pos].
@@ -865,17 +866,17 @@
// RAX is arg_pos as Smi.
// Point to next named entry.
__ AddImmediate(
- RDI, Immediate(ArgumentsDescriptor::named_entry_size()), PP);
+ RDI, Immediate(ArgumentsDescriptor::named_entry_size()));
__ negq(RAX);
Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi.
__ movq(RAX, argument_addr);
__ jmp(&assign_optional_parameter, Assembler::kNearJump);
__ Bind(&load_default_value);
// Load RAX with default argument.
- const Object& value = Object::ZoneHandle(
+ const Object& value = Object::ZoneHandle(zone(),
parsed_function().default_parameter_values().At(
param_pos - num_fixed_params));
- __ LoadObject(RAX, value, PP);
+ __ LoadObject(RAX, value);
__ Bind(&assign_optional_parameter);
// Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
@@ -890,7 +891,7 @@
if (check_correct_named_args) {
// Check that RDI now points to the null terminator in the arguments
// descriptor.
- __ LoadObject(TMP, Object::null_object(), PP);
+ __ LoadObject(TMP, Object::null_object());
__ cmpq(Address(RDI, 0), TMP);
__ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
}
@@ -905,12 +906,12 @@
// arguments have been passed, where k is param_pos, the position of this
// optional parameter in the formal parameter list.
const int param_pos = num_fixed_params + i;
- __ CompareImmediate(RCX, Immediate(param_pos), PP);
+ __ CompareImmediate(RCX, Immediate(param_pos));
__ j(GREATER, &next_parameter, Assembler::kNearJump);
// Load RAX with default argument.
- const Object& value = Object::ZoneHandle(
+ const Object& value = Object::ZoneHandle(zone(),
parsed_function().default_parameter_values().At(i));
- __ LoadObject(RAX, value, PP);
+ __ LoadObject(RAX, value);
// Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
// scope->VariableAt(i)->index(), because captured variables still need
@@ -931,8 +932,11 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
+ ASSERT(assembler()->constant_pool_allowed());
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ jmp(&isolate()->stub_code()->CallClosureNoSuchMethodLabel());
+ ASSERT(!assembler()->constant_pool_allowed());
+ __ jmp(*StubCode::CallClosureNoSuchMethod_entry());
+ __ set_constant_pool_allowed(true);
// The noSuchMethod call may return to the caller, but not here.
} else if (check_correct_named_args) {
__ Stop("Wrong arguments");
@@ -948,7 +952,7 @@
// R10 : arguments descriptor array.
__ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
__ SmiUntag(RCX);
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
Label null_args_loop, null_args_loop_condition;
__ jmp(&null_args_loop_condition, Assembler::kNearJump);
const Address original_argument_addr(
@@ -981,7 +985,7 @@
__ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver.
__ movq(RBX, Address(RSP, 1 * kWordSize)); // Value.
__ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX);
- __ LoadObject(RAX, Object::null_object(), PP);
+ __ LoadObject(RAX, Object::null_object());
__ ret();
}
@@ -1018,7 +1022,7 @@
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = RDI;
// Load function object using the callee's pool pointer.
- __ LoadObject(function_reg, function, new_pp);
+ __ LoadFunctionFromCalleePool(function_reg, function, new_pp);
// Patch point is after the eventually inlined function object.
entry_patch_pc_offset_ = assembler()->CodeSize();
@@ -1033,7 +1037,7 @@
Immediate(GetOptimizationThreshold()));
ASSERT(function_reg == RDI);
__ J(GREATER_EQUAL,
- &isolate()->stub_code()->OptimizeFunctionLabel(),
+ *StubCode::OptimizeFunction_entry(),
new_pp);
} else {
entry_patch_pc_offset_ = assembler()->CodeSize();
@@ -1051,13 +1055,13 @@
TryIntrinsify();
EmitFrameEntry();
+ ASSERT(assembler()->constant_pool_allowed());
const Function& function = parsed_function().function();
const int num_fixed_params = function.num_fixed_parameters();
const int num_copied_params = parsed_function().num_copied_params();
const int num_locals = parsed_function().num_stack_locals();
- StubCode* stub_code = isolate()->stub_code();
// We check the number of passed arguments when we have to copy them due to
// the presence of optional parameters.
@@ -1076,7 +1080,7 @@
// Check that exactly num_fixed arguments are passed in.
Label correct_num_arguments, wrong_num_arguments;
__ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
- __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params)), PP);
+ __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params)));
__ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump);
__ cmpq(RAX,
FieldAddress(R10,
@@ -1085,8 +1089,11 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction()) {
+ ASSERT(assembler()->constant_pool_allowed());
__ LeaveDartFrame(); // The arguments are still on the stack.
- __ jmp(&stub_code->CallClosureNoSuchMethodLabel());
+ ASSERT(!assembler()->constant_pool_allowed());
+ __ jmp(*StubCode::CallClosureNoSuchMethod_entry());
+ __ set_constant_pool_allowed(true);
// The noSuchMethod call may return to the caller, but not here.
} else {
__ Stop("Wrong number of arguments");
@@ -1122,7 +1129,7 @@
const intptr_t context_index =
parsed_function().current_context_var()->index();
if (num_locals > 1) {
- __ LoadObject(RAX, Object::null_object(), PP);
+ __ LoadObject(RAX, Object::null_object());
}
for (intptr_t i = 0; i < num_locals; ++i) {
// Subtract index i (locals lie at lower addresses than RBP).
@@ -1133,7 +1140,7 @@
const Context& empty_context = Context::ZoneHandle(
zone(), isolate()->object_store()->empty_context());
__ StoreObject(
- Address(RBP, (slot_base - i) * kWordSize), empty_context, PP);
+ Address(RBP, (slot_base - i) * kWordSize), empty_context);
}
} else {
ASSERT(num_locals > 1);
@@ -1146,26 +1153,27 @@
VisitBlocks();
__ int3();
+ ASSERT(assembler()->constant_pool_allowed());
GenerateDeferredCode();
// Emit function patching code. This will be swapped with the first 13 bytes
// at entry point.
patch_code_pc_offset_ = assembler()->CodeSize();
// This is patched up to a point in FrameEntry where the PP for the
// current function is in R13 instead of PP.
- __ JmpPatchable(&stub_code->FixCallersTargetLabel(), R13);
+ __ JmpPatchable(*StubCode::FixCallersTarget_entry(), R13);
if (is_optimizing()) {
lazy_deopt_pc_offset_ = assembler()->CodeSize();
- __ Jmp(&stub_code->DeoptimizeLazyLabel(), PP);
+ __ Jmp(*StubCode::DeoptimizeLazy_entry(), PP);
}
}
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ Call(label, PP);
+ __ Call(stub_entry);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}
@@ -1173,10 +1181,10 @@
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
intptr_t token_pos,
- const ExternalLabel* label,
+ const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ CallPatchable(label);
+ __ CallPatchable(stub_entry);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
// Marks either the continuation point in unoptimized code or the
@@ -1221,14 +1229,12 @@
intptr_t token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- StubCode* stub_code = isolate()->stub_code();
- const uword label_address =
- stub_code->UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
- ExternalLabel target_label(label_address);
- __ LoadObject(RBX, ic_data, PP);
+ const StubEntry* stub_entry =
+ StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
+ __ LoadObject(RBX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- &target_label,
+ *stub_entry,
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count, RCX);
@@ -1241,10 +1247,11 @@
// overflow; and though we do not reset the counters when we optimize or
// deoptimize, there is a bound on the number of
// optimization/deoptimization cycles we will attempt.
- const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
- counter.SetAt(0, Smi::Handle(Smi::New(0)));
+ ASSERT(assembler_->constant_pool_allowed());
+ const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld));
+ counter.SetAt(0, Smi::Handle(zone(), Smi::New(0)));
__ Comment("Edge counter");
- __ LoadUniqueObject(RAX, counter, PP);
+ __ LoadUniqueObject(RAX, counter);
intptr_t increment_start = assembler_->CodeSize();
__ IncrementSmiField(FieldAddress(RAX, Array::element_offset(0)), 1);
int32_t size = assembler_->CodeSize() - increment_start;
@@ -1264,41 +1271,41 @@
void FlowGraphCompiler::EmitOptimizedInstanceCall(
- ExternalLabel* target_label,
+ const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
// to inlining in optimized code, that function may not correspond to the
// top-level function (parsed_function().function()) which could be
// reoptimized and which counter needs to be incremented.
// Pass the function explicitly, it is used in IC stub.
- __ LoadObject(RDI, parsed_function().function(), PP);
- __ LoadUniqueObject(RBX, ic_data, PP);
+ __ LoadObject(RDI, parsed_function().function());
+ __ LoadUniqueObject(RBX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count, RCX);
}
-void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
+void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
- __ LoadUniqueObject(RBX, ic_data, PP);
+ ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
+ __ LoadUniqueObject(RBX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
- target_label,
+ stub_entry,
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count, RCX);
@@ -1312,26 +1319,25 @@
intptr_t token_pos,
LocationSummary* locs) {
MegamorphicCacheTable* table = isolate()->megamorphic_cache_table();
- const String& name = String::Handle(ic_data.target_name());
+ const String& name = String::Handle(zone(), ic_data.target_name());
const Array& arguments_descriptor =
- Array::ZoneHandle(ic_data.arguments_descriptor());
+ Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
- const MegamorphicCache& cache =
- MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
+ const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
+ zone(), table->Lookup(name, arguments_descriptor));
const Register receiverR = RDI;
const Register cacheR = RBX;
const Register targetR = RCX;
__ movq(receiverR, Address(RSP, (argument_count - 1) * kWordSize));
- __ LoadObject(cacheR, cache, PP);
+ __ LoadObject(cacheR, cache);
if (FLAG_use_megamorphic_stub) {
- StubCode* stub_code = isolate()->stub_code();
- __ call(&stub_code->MegamorphicLookupLabel());
+ __ Call(*StubCode::MegamorphicLookup_entry());
} else {
StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR);
}
- __ LoadObject(RBX, ic_data, PP);
- __ LoadObject(R10, arguments_descriptor, PP);
+ __ LoadObject(RBX, ic_data);
+ __ LoadObject(R10, arguments_descriptor);
__ call(targetR);
AddCurrentDescriptor(RawPcDescriptors::kOther,
Isolate::kNoDeoptId, token_pos);
@@ -1355,13 +1361,12 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- StubCode* stub_code = isolate()->stub_code();
- __ LoadObject(R10, arguments_descriptor, PP);
+ __ LoadObject(R10, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_pos,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
AddStaticCallTarget(function);
@@ -1384,13 +1389,12 @@
}
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ pushq(reg);
- __ PushObject(obj, PP);
+ __ PushObject(obj);
if (is_optimizing()) {
- __ CallPatchable(&stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
- __ CallPatchable(&stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1401,7 +1405,7 @@
__ popq(reg); // Discard constant.
__ popq(reg); // Restore 'reg'.
} else {
- __ CompareObject(reg, obj, PP);
+ __ CompareObject(reg, obj);
}
return EQUAL;
}
@@ -1412,13 +1416,12 @@
bool needs_number_check,
intptr_t token_pos) {
if (needs_number_check) {
- StubCode* stub_code = isolate()->stub_code();
__ pushq(left);
__ pushq(right);
if (is_optimizing()) {
- __ CallPatchable(&stub_code->OptimizedIdenticalWithNumberCheckLabel());
+ __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
} else {
- __ CallPatchable(&stub_code->UnoptimizedIdenticalWithNumberCheckLabel());
+ __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
}
if (token_pos != Scanner::kNoSourcePos) {
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
@@ -1482,13 +1485,12 @@
__ Comment("EmitTestAndCall");
const Array& arguments_descriptor =
- Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
- argument_names));
- StubCode* stub_code = isolate()->stub_code();
+ Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count,
+ argument_names));
// Load receiver into RAX.
__ movq(RAX,
Address(RSP, (argument_count - 1) * kWordSize));
- __ LoadObject(R10, arguments_descriptor, PP);
+ __ LoadObject(R10, arguments_descriptor);
const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid;
const intptr_t kNumChecks = ic_data.NumberOfChecks();
@@ -1508,10 +1510,10 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
- const Function& function = Function::Handle(ic_data.GetTargetAt(0));
+ const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0));
AddStaticCallTarget(function);
__ Drop(argument_count, RCX);
if (kNumChecks > 1) {
@@ -1549,7 +1551,7 @@
// that we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
token_index,
- &stub_code->CallStaticFunctionLabel(),
+ *StubCode::CallStaticFunction_entry(),
RawPcDescriptors::kOther,
locs);
const Function& function = *sorted[i].target;
@@ -1626,13 +1628,13 @@
(source.constant_instruction()->representation() == kUnboxedInt32)) {
__ movl(destination.reg(), Immediate(Smi::Cast(constant).Value()));
} else {
- __ LoadObject(destination.reg(), constant, PP);
+ __ LoadObject(destination.reg(), constant);
}
} else if (destination.IsFpuRegister()) {
if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) {
__ xorps(destination.fpu_reg(), destination.fpu_reg());
} else {
- __ LoadObject(TMP, constant, PP);
+ __ LoadObject(TMP, constant);
__ movsd(destination.fpu_reg(),
FieldAddress(TMP, Double::value_offset()));
}
@@ -1640,7 +1642,7 @@
if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) {
__ xorps(XMM0, XMM0);
} else {
- __ LoadObject(TMP, constant, PP);
+ __ LoadObject(TMP, constant);
__ movsd(XMM0, FieldAddress(TMP, Double::value_offset()));
}
__ movsd(destination.ToStackSlotAddress(), XMM0);
@@ -1745,7 +1747,7 @@
void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
- __ StoreObject(dst, obj, PP);
+ __ StoreObject(dst, obj);
}
@@ -1785,14 +1787,14 @@
void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
- __ AddImmediate(RSP, Immediate(-kFpuRegisterSize), PP);
+ __ AddImmediate(RSP, Immediate(-kFpuRegisterSize));
__ movups(Address(RSP, 0), reg);
}
void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
__ movups(reg, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(kFpuRegisterSize), PP);
+ __ AddImmediate(RSP, Immediate(kFpuRegisterSize));
}
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index f22c50f..6fcd874 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -1038,10 +1038,9 @@
}
const AbstractType* abstract_type = NULL;
- if (Isolate::Current()->flags().type_checks()) {
- ASSERT(!type().HasResolvedTypeClass() ||
- !Field::IsExternalizableCid(Class::Handle(
- type().type_class()).id()));
+ if (Isolate::Current()->flags().type_checks() &&
+ type().HasResolvedTypeClass() &&
+ !Field::IsExternalizableCid(Class::Handle(type().type_class()).id())) {
abstract_type = &type();
}
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index d7e05f1..12ad8c4 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -317,10 +317,9 @@
// If the code wasn't strongly visited through other references
// after skipping the function's code pointer, then we disconnect the
// code from the function.
- StubCode* stub_code = isolate()->stub_code();
func->StorePointer(
&(func->ptr()->instructions_),
- stub_code->LazyCompile_entry()->code()->ptr()->instructions_);
+ StubCode::LazyCompile_entry()->code()->ptr()->instructions_);
if (FLAG_log_code_drop) {
// NOTE: This code runs while GC is in progress and runs within
// a NoHandleScope block. Hence it is not okay to use a regular Zone
diff --git a/runtime/vm/gc_marker.h b/runtime/vm/gc_marker.h
index 95666b3..978cf3d 100644
--- a/runtime/vm/gc_marker.h
+++ b/runtime/vm/gc_marker.h
@@ -48,7 +48,7 @@
Heap* heap_;
- intptr_t marked_bytes_;
+ uintptr_t marked_bytes_;
DISALLOW_IMPLICIT_CONSTRUCTORS(GCMarker);
};
diff --git a/runtime/vm/handles.cc b/runtime/vm/handles.cc
index f636fdd..c053542 100644
--- a/runtime/vm/handles.cc
+++ b/runtime/vm/handles.cc
@@ -76,17 +76,17 @@
int VMHandles::ScopedHandleCount() {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate->current_zone() != NULL);
- VMHandles* handles = isolate->current_zone()->handles();
+ Thread* thread = Thread::Current();
+ ASSERT(thread->zone() != NULL);
+ VMHandles* handles = thread->zone()->handles();
return handles->CountScopedHandles();
}
int VMHandles::ZoneHandleCount() {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate->current_zone() != NULL);
- VMHandles* handles = isolate->current_zone()->handles();
+ Thread* thread = Thread::Current();
+ ASSERT(thread->zone() != NULL);
+ VMHandles* handles = thread->zone()->handles();
return handles->CountZoneHandles();
}
diff --git a/runtime/vm/handles_impl.h b/runtime/vm/handles_impl.h
index 370b34e..ad005bb 100644
--- a/runtime/vm/handles_impl.h
+++ b/runtime/vm/handles_impl.h
@@ -123,18 +123,18 @@
}
-// Figure out the current zone using the current Isolate and
+// Figure out the current zone using the current Thread and
// check if the specified handle has been allocated in this zone.
template <int kHandleSizeInWords, int kHandlesPerChunk, int kOffsetOfRawPtr>
bool Handles<kHandleSizeInWords,
kHandlesPerChunk,
kOffsetOfRawPtr>::IsZoneHandle(uword handle) {
- // TODO(5411412): Accessing the current isolate is a performance problem,
+ // TODO(5411412): Accessing the current thread is a performance problem,
// consider passing it down as a parameter.
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- ASSERT(isolate->current_zone() != NULL);
- Handles* handles = isolate->current_zone()->handles();
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ ASSERT(thread->zone() != NULL);
+ Handles* handles = thread->zone()->handles();
ASSERT(handles != NULL);
return handles->IsValidZoneHandle(handle);
}
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 06da6f1..6897af8 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -74,7 +74,9 @@
uword Heap::AllocateNew(intptr_t size) {
- ASSERT(isolate()->no_safepoint_scope_depth() == 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
+ // Currently, only the Dart thread may allocate in new space.
+ isolate()->AssertCurrentThreadIsMutator();
uword addr = new_space_.TryAllocate(size);
if (addr == 0) {
CollectGarbage(kNew);
@@ -88,7 +90,13 @@
uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) {
- ASSERT(isolate()->no_safepoint_scope_depth() == 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
+#if defined(DEBUG)
+ // Currently, allocation from non-Dart threads must not trigger GC.
+ if (GrowthControlState()) {
+ isolate()->AssertCurrentThreadIsMutator();
+ }
+#endif
uword addr = old_space_.TryAllocate(size, type);
if (addr != 0) {
return addr;
@@ -149,7 +157,7 @@
uword Heap::AllocatePretenured(intptr_t size) {
- ASSERT(isolate()->no_safepoint_scope_depth() == 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
uword addr = old_space_.TryAllocateDataBump(size, PageSpace::kControlGrowth);
if (addr != 0) return addr;
return AllocateOld(size, HeapPage::kData);
@@ -157,7 +165,7 @@
void Heap::AllocateExternal(intptr_t size, Space space) {
- ASSERT(isolate()->no_safepoint_scope_depth() == 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
if (space == kNew) {
new_space_.AllocateExternal(size);
if (new_space_.ExternalInWords() > (FLAG_new_gen_ext_limit * MBInWords)) {
@@ -216,7 +224,7 @@
HeapIterationScope::HeapIterationScope()
- : StackResource(Thread::Current()->isolate()),
+ : StackResource(Thread::Current()),
old_space_(isolate()->heap()->old_space()) {
// It's not yet safe to iterate over a paged space while it's concurrently
// sweeping, so wait for any such task to complete first.
@@ -444,26 +452,6 @@
}
-uword Heap::TopAddress(Heap::Space space) {
- if (space == kNew) {
- return reinterpret_cast<uword>(new_space_.TopAddress());
- } else {
- ASSERT(space == kPretenured);
- return reinterpret_cast<uword>(old_space_.TopAddress());
- }
-}
-
-
-uword Heap::EndAddress(Heap::Space space) {
- if (space == kNew) {
- return reinterpret_cast<uword>(new_space_.EndAddress());
- } else {
- ASSERT(space == kPretenured);
- return reinterpret_cast<uword>(old_space_.EndAddress());
- }
-}
-
-
Heap::Space Heap::SpaceForAllocation(intptr_t cid) {
return FLAG_pretenure_all ? kPretenured : kNew;
}
@@ -759,13 +747,13 @@
#if defined(DEBUG)
-NoSafepointScope::NoSafepointScope() : StackResource(Isolate::Current()) {
- isolate()->IncrementNoSafepointScopeDepth();
+NoSafepointScope::NoSafepointScope() : StackResource(Thread::Current()) {
+ thread()->IncrementNoSafepointScopeDepth();
}
NoSafepointScope::~NoSafepointScope() {
- isolate()->DecrementNoSafepointScopeDepth();
+ thread()->DecrementNoSafepointScopeDepth();
}
#endif // defined(DEBUG)
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 076b283..05e0ef0 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -140,9 +140,7 @@
}
// Accessors for inlined allocation in generated code.
- uword TopAddress(Space space);
static intptr_t TopOffset(Space space);
- uword EndAddress(Space space);
static intptr_t EndOffset(Space space);
static Space SpaceForAllocation(intptr_t class_id);
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index 11f2d4f..47cfafe 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -213,7 +213,9 @@
public:
FindOnly(Isolate* isolate, RawObject* target)
: FindObjectVisitor(isolate), target_(target) {
- ASSERT(isolate->no_safepoint_scope_depth() != 0);
+#if defined(DEBUG)
+ EXPECT_GT(Thread::Current()->no_safepoint_scope_depth(), 0);
+#endif
}
virtual ~FindOnly() { }
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 6a5ce90..9c0a808 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -15,6 +15,8 @@
DEFINE_FLAG(charp, print_flow_graph_filter, NULL,
"Print only IR of functions with matching names");
+DECLARE_FLAG(bool, trace_inlining_intervals);
+
void BufferFormatter::Print(const char* format, ...) {
va_list args;
va_start(args, format);
@@ -136,6 +138,9 @@
}
if (!instr->IsBlockEntry()) ISL_Print(" ");
ISL_Print("%s", str);
+ if (FLAG_trace_inlining_intervals) {
+ ISL_Print(" iid: %" Pd "", instr->inlining_id());
+ }
}
diff --git a/runtime/vm/instructions_arm64_test.cc b/runtime/vm/instructions_arm64_test.cc
index 263c6a4..924d495 100644
--- a/runtime/vm/instructions_arm64_test.cc
+++ b/runtime/vm/instructions_arm64_test.cc
@@ -16,8 +16,9 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchLinkPatchable(&stub_code->InvokeDartCodeLabel());
+ // Code accessing pp is generated, but not executed. Uninitialized pp is OK.
+ __ set_constant_pool_allowed(true);
+ __ BranchLinkPatchable(*StubCode::InvokeDartCode_entry());
__ ret();
}
@@ -28,18 +29,14 @@
// before the end of the code buffer.
CallPattern call(test->entry() + test->code().Size() - Instr::kInstrSize,
test->code());
- StubCode* stub_code = Isolate::Current()->stub_code();
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
call.TargetAddress());
}
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->InvokeDartCodeLabel());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchPatchable(&array_label);
+ __ BranchPatchable(*StubCode::InvokeDartCode_entry());
+ __ BranchPatchable(*StubCode::AllocateArray_entry());
}
@@ -50,21 +47,21 @@
VirtualMemory::Protect(reinterpret_cast<void*>(instrs.EntryPoint()),
instrs.size(),
VirtualMemory::kReadWrite);
- StubCode* stub_code = Isolate::Current()->stub_code();
EXPECT(status);
JumpPattern jump1(test->entry(), test->code());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
+ const Code& array_stub =
+ Code::Handle(StubCode::AllocateArray_entry()->code());
EXPECT_EQ(array_stub.EntryPoint(), jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
uword target2 = jump2.TargetAddress();
jump1.SetTargetAddress(target2);
jump2.SetTargetAddress(target1);
EXPECT_EQ(array_stub.EntryPoint(), jump1.TargetAddress());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump2.TargetAddress());
}
diff --git a/runtime/vm/instructions_arm_test.cc b/runtime/vm/instructions_arm_test.cc
index dcee850..540fd5f 100644
--- a/runtime/vm/instructions_arm_test.cc
+++ b/runtime/vm/instructions_arm_test.cc
@@ -16,8 +16,9 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchLinkPatchable(&stub_code->InvokeDartCodeLabel());
+ // Code accessing pp is generated, but not executed. Uninitialized pp is OK.
+ __ set_constant_pool_allowed(true);
+ __ BranchLinkPatchable(*StubCode::InvokeDartCode_entry());
__ Ret();
}
@@ -28,18 +29,14 @@
// before the end of the code buffer.
CallPattern call(test->entry() + test->code().Size() - Instr::kInstrSize,
test->code());
- StubCode* stub_code = Isolate::Current()->stub_code();
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
call.TargetAddress());
}
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->InvokeDartCodeLabel());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchPatchable(&array_label);
+ __ BranchPatchable(*StubCode::InvokeDartCode_entry());
+ __ BranchPatchable(*StubCode::AllocateArray_entry());
}
@@ -50,21 +47,21 @@
VirtualMemory::Protect(reinterpret_cast<void*>(instrs.EntryPoint()),
instrs.size(),
VirtualMemory::kReadWrite);
- StubCode* stub_code = Isolate::Current()->stub_code();
EXPECT(status);
JumpPattern jump1(test->entry(), test->code());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
+ const Code& array_stub =
+ Code::Handle(StubCode::AllocateArray_entry()->code());
EXPECT_EQ(array_stub.EntryPoint(), jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
uword target2 = jump2.TargetAddress();
jump1.SetTargetAddress(target2);
jump2.SetTargetAddress(target1);
EXPECT_EQ(array_stub.EntryPoint(), jump1.TargetAddress());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump2.TargetAddress());
}
@@ -72,12 +69,9 @@
#if defined(USING_SIMULATOR)
ASSEMBLER_TEST_GENERATE(JumpARMv6, assembler) {
// ARMv7 is the default.
- StubCode* stub_code = Isolate::Current()->stub_code();
HostCPUFeatures::set_arm_version(ARMv6);
- __ BranchPatchable(&stub_code->InvokeDartCodeLabel());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchPatchable(&array_label);
+ __ BranchPatchable(*StubCode::InvokeDartCode_entry());
+ __ BranchPatchable(*StubCode::AllocateArray_entry());
HostCPUFeatures::set_arm_version(ARMv7);
}
@@ -90,21 +84,21 @@
VirtualMemory::Protect(reinterpret_cast<void*>(instrs.EntryPoint()),
instrs.size(),
VirtualMemory::kReadWrite);
- StubCode* stub_code = Isolate::Current()->stub_code();
EXPECT(status);
JumpPattern jump1(test->entry(), test->code());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
+ const Code& array_stub =
+ Code::Handle(StubCode::AllocateArray_entry()->code());
EXPECT_EQ(array_stub.EntryPoint(), jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
uword target2 = jump2.TargetAddress();
jump1.SetTargetAddress(target2);
jump2.SetTargetAddress(target1);
EXPECT_EQ(array_stub.EntryPoint(), jump1.TargetAddress());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump2.TargetAddress());
HostCPUFeatures::set_arm_version(ARMv7);
}
diff --git a/runtime/vm/instructions_ia32_test.cc b/runtime/vm/instructions_ia32_test.cc
index 27c5277..cace229 100644
--- a/runtime/vm/instructions_ia32_test.cc
+++ b/runtime/vm/instructions_ia32_test.cc
@@ -17,26 +17,22 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ call(&stub_code->InvokeDartCodeLabel());
+ __ Call(*StubCode::InvokeDartCode_entry());
__ ret();
}
ASSEMBLER_TEST_RUN(Call, test) {
- StubCode* stub_code = Isolate::Current()->stub_code();
CallPattern call(test->entry());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->EntryPoint(),
call.TargetAddress());
}
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ jmp(&stub_code->InvokeDartCodeLabel());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ jmp(&array_label);
+ __ Jmp(*StubCode::InvokeDartCode_entry());
+ const ExternalLabel label(StubCode::AllocateArray_entry()->EntryPoint());
+ __ jmp(&label);
__ ret();
}
@@ -44,18 +40,18 @@
ASSEMBLER_TEST_RUN(Jump, test) {
const Code& code = test->code();
const Instructions& instrs = Instructions::Handle(code.instructions());
- StubCode* stub_code = Isolate::Current()->stub_code();
bool status =
VirtualMemory::Protect(reinterpret_cast<void*>(instrs.EntryPoint()),
instrs.size(),
VirtualMemory::kReadWrite);
EXPECT(status);
JumpPattern jump1(test->entry(), test->code());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->EntryPoint(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
+ const Code& array_stub =
+ Code::Handle(StubCode::AllocateArray_entry()->code());
EXPECT_EQ(array_stub.EntryPoint(),
jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
@@ -64,7 +60,7 @@
jump2.SetTargetAddress(target1);
EXPECT_EQ(array_stub.EntryPoint(),
jump1.TargetAddress());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->EntryPoint(),
jump2.TargetAddress());
}
diff --git a/runtime/vm/instructions_mips_test.cc b/runtime/vm/instructions_mips_test.cc
index 6c6fe07..a165485 100644
--- a/runtime/vm/instructions_mips_test.cc
+++ b/runtime/vm/instructions_mips_test.cc
@@ -15,8 +15,7 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchLinkPatchable(&stub_code->InvokeDartCodeLabel());
+ __ BranchLinkPatchable(*StubCode::InvokeDartCode_entry());
__ Ret();
}
@@ -28,18 +27,14 @@
// return jump.
CallPattern call(test->entry() + test->code().Size() - (2*Instr::kInstrSize),
test->code());
- StubCode* stub_code = Isolate::Current()->stub_code();
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
call.TargetAddress());
}
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->InvokeDartCodeLabel());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchPatchable(&array_label);
+ __ BranchPatchable(*StubCode::InvokeDartCode_entry());
+ __ BranchPatchable(*StubCode::AllocateArray_entry());
}
@@ -50,21 +45,21 @@
VirtualMemory::Protect(reinterpret_cast<void*>(instrs.EntryPoint()),
instrs.size(),
VirtualMemory::kReadWrite);
- StubCode* stub_code = Isolate::Current()->stub_code();
EXPECT(status);
JumpPattern jump1(test->entry(), test->code());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
+ const Code& array_stub =
+ Code::Handle(StubCode::AllocateArray_entry()->code());
EXPECT_EQ(array_stub.EntryPoint(), jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
uword target2 = jump2.TargetAddress();
jump1.SetTargetAddress(target2);
jump2.SetTargetAddress(target1);
EXPECT_EQ(array_stub.EntryPoint(), jump1.TargetAddress());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump2.TargetAddress());
}
diff --git a/runtime/vm/instructions_x64_test.cc b/runtime/vm/instructions_x64_test.cc
index b9e3eb2..0ad8294 100644
--- a/runtime/vm/instructions_x64_test.cc
+++ b/runtime/vm/instructions_x64_test.cc
@@ -15,8 +15,7 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ call(&stub_code->InvokeDartCodeLabel());
+ __ Call(*StubCode::InvokeDartCode_entry());
__ ret();
}
@@ -27,13 +26,10 @@
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
ASSERT(assembler->CodeSize() == 0);
__ pushq(PP);
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
prologue_code_size = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ JmpPatchable(&stub_code->InvokeDartCodeLabel(), PP);
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ JmpPatchable(&array_label, PP);
+ __ JmpPatchable(*StubCode::InvokeDartCode_entry(), PP);
+ __ JmpPatchable(*StubCode::AllocateArray_entry(), PP);
__ popq(PP);
__ ret();
}
@@ -43,7 +39,6 @@
ASSERT(prologue_code_size != -1);
const Code& code = test->code();
const Instructions& instrs = Instructions::Handle(code.instructions());
- StubCode* stub_code = Isolate::Current()->stub_code();
bool status =
VirtualMemory::Protect(reinterpret_cast<void*>(instrs.EntryPoint()),
instrs.size(),
@@ -51,19 +46,20 @@
EXPECT(status);
JumpPattern jump1(test->entry() + prologue_code_size, test->code());
jump1.IsValid();
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump1.TargetAddress());
JumpPattern jump2((test->entry() +
jump1.pattern_length_in_bytes() + prologue_code_size),
test->code());
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
+ const Code& array_stub =
+ Code::Handle(StubCode::AllocateArray_entry()->code());
EXPECT_EQ(array_stub.EntryPoint(), jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
uword target2 = jump2.TargetAddress();
jump1.SetTargetAddress(target2);
jump2.SetTargetAddress(target1);
EXPECT_EQ(array_stub.EntryPoint(), jump1.TargetAddress());
- EXPECT_EQ(stub_code->InvokeDartCodeLabel().address(),
+ EXPECT_EQ(StubCode::InvokeDartCode_entry()->label().address(),
jump2.TargetAddress());
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index a5e7f5e..b7bacba 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -49,7 +49,19 @@
ssa_temp_index_(-1),
input_use_list_(NULL),
env_use_list_(NULL),
- constant_value_(Object::ZoneHandle(ConstantPropagator::Unknown())) {
+ constant_value_(NULL) {
+}
+
+
+// A value in the constant propagation lattice.
+// - non-constant sentinel
+// - a constant (any non-sentinel value)
+// - unknown sentinel
+Object& Definition::constant_value() {
+ if (constant_value_ == NULL) {
+ constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown());
+ }
+ return *constant_value_;
}
@@ -2933,16 +2945,15 @@
}
-static uword TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
+static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
if (!FLAG_two_args_smi_icd) {
return 0;
}
- StubCode* stub_code = Isolate::Current()->stub_code();
switch (kind) {
- case Token::kADD: return stub_code->SmiAddInlineCacheEntryPoint();
- case Token::kSUB: return stub_code->SmiSubInlineCacheEntryPoint();
- case Token::kEQ: return stub_code->SmiEqualInlineCacheEntryPoint();
- default: return 0;
+ case Token::kADD: return StubCode::SmiAddInlineCache_entry();
+ case Token::kSUB: return StubCode::SmiSubInlineCache_entry();
+ case Token::kEQ: return StubCode::SmiEqualInlineCache_entry();
+ default: return NULL;
}
}
@@ -2983,8 +2994,8 @@
// Unoptimized code.
ASSERT(!HasICData());
bool is_smi_two_args_op = false;
- const uword label_address = TwoArgsSmiOpInlineCacheEntry(token_kind());
- if (label_address != 0) {
+ const StubEntry* stub_entry = TwoArgsSmiOpInlineCacheEntry(token_kind());
+ if (stub_entry != NULL) {
// We have a dedicated inline cache stub for this operation, add an
// an initial Smi/Smi check with count 0.
ASSERT(call_ic_data->NumArgsTested() == 2);
@@ -3012,8 +3023,7 @@
}
if (is_smi_two_args_op) {
ASSERT(ArgumentCount() == 2);
- ExternalLabel target_label(label_address);
- compiler->EmitInstanceCall(&target_label, *call_ic_data, ArgumentCount(),
+ compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(),
deopt_id(), token_pos(), locs());
} else if (FLAG_ic_range_profiling &&
(Token::IsBinaryArithmeticOperator(token_kind()) ||
@@ -3022,11 +3032,10 @@
(ArgumentCount() == 1));
ASSERT(Token::IsBinaryArithmeticOperator(token_kind()) ==
(ArgumentCount() == 2));
- StubCode* stub_code = compiler->isolate()->stub_code();
- ExternalLabel target_label((ArgumentCount() == 1) ?
- stub_code->UnaryRangeCollectingInlineCacheEntryPoint() :
- stub_code->BinaryRangeCollectingInlineCacheEntryPoint());
- compiler->EmitInstanceCall(&target_label, *call_ic_data, ArgumentCount(),
+ const StubEntry* stub_entry = (ArgumentCount() == 1)
+ ? StubCode::UnaryRangeCollectingInlineCache_entry()
+ : StubCode::BinaryRangeCollectingInlineCache_entry();
+ compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(),
deopt_id(), token_pos(), locs());
} else {
compiler->GenerateInstanceCall(deopt_id(),
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index c943680..44919ff 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -1748,7 +1748,7 @@
// - non-constant sentinel
// - a constant (any non-sentinel value)
// - unknown sentinel
- Object& constant_value() const { return constant_value_; }
+ Object& constant_value();
virtual void InferRange(RangeAnalysis* analysis, Range* range);
@@ -1801,7 +1801,7 @@
Value* input_use_list_;
Value* env_use_list_;
- Object& constant_value_;
+ Object* constant_value_;
DISALLOW_COPY_AND_ASSIGN(Definition);
};
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 6538dec..1db4ad1 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -104,8 +104,12 @@
__ bkpt(0);
__ Bind(&stack_ok);
#endif
- __ LeaveDartFrame();
+ ASSERT(__ constant_pool_allowed());
+ __ LeaveDartFrame(); // Disallows constant pool use.
__ Ret();
+ // This ReturnInstr may be emitted out of order by the optimizer. The next
+ // block may be a target expecting a properly set constant pool pointer.
+ __ set_constant_pool_allowed(true);
}
@@ -938,10 +942,9 @@
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
const bool is_leaf_call =
(argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel* stub_entry;
+ const StubEntry* stub_entry = NULL;
if (is_bootstrap_native() || is_leaf_call) {
- stub_entry = &stub_code->CallBootstrapCFunctionLabel();
+ stub_entry = StubCode::CallBootstrapCFunction_entry();
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kBootstrapNativeCall, function().NumParameters());
@@ -950,7 +953,7 @@
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = &stub_code->CallNativeCFunctionLabel();
+ stub_entry = StubCode::CallNativeCFunction_entry();
#if defined(USING_SIMULATOR)
if (!function().IsNativeAutoSetupScope()) {
entry = Simulator::RedirectExternalReference(
@@ -961,7 +964,7 @@
__ LoadImmediate(R5, entry);
__ LoadImmediate(R1, argc_tag);
compiler->GenerateCall(token_pos(),
- stub_entry,
+ *stub_entry,
RawPcDescriptors::kOther,
locs());
__ Pop(result);
@@ -980,6 +983,7 @@
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(compiler->is_optimizing());
const Register char_code = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
__ LoadImmediate(result,
@@ -1808,7 +1812,6 @@
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
@@ -1817,8 +1820,8 @@
}
__ Bind(entry_label());
const Code& stub =
- Code::Handle(isolate, stub_code->GetAllocationStubForClass(cls_));
- const ExternalLabel label(stub.EntryPoint());
+ Code::Handle(isolate, StubCode::GetAllocationStubForClass(cls_));
+ const StubEntry stub_entry(stub);
LocationSummary* locs = instruction_->locs();
@@ -1826,9 +1829,10 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs);
+ compiler->AddStubCallTarget(stub);
__ MoveRegister(result_, R0);
compiler->RestoreLiveRegisters(locs);
__ b(exit_label());
@@ -2389,15 +2393,10 @@
return;
}
}
- Isolate* isolate = compiler->isolate();
- const Code& stub = Code::Handle(
- isolate, isolate->stub_code()->GetAllocateArrayStub());
- const ExternalLabel label(stub.EntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
locs());
- compiler->AddStubCallTarget(stub);
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2681,10 +2680,8 @@
compiler->SaveLiveRegisters(locs);
__ LoadImmediate(R1, instruction_->num_context_variables());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
compiler->GenerateCall(instruction_->token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs);
ASSERT(instruction_->locs()->out(0).reg() == R0);
@@ -2739,10 +2736,8 @@
ASSERT(locs()->out(0).reg() == R0);
__ LoadImmediate(R1, num_context_variables());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs());
}
@@ -2919,8 +2914,13 @@
CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
compiler->AddSlowPathCode(slow_path);
- __ LoadImmediate(IP, Isolate::Current()->stack_limit_address());
- __ ldr(IP, Address(IP));
+ if (compiler->is_optimizing()) {
+ __ LoadImmediate(IP, Isolate::Current()->stack_limit_address());
+ __ ldr(IP, Address(IP));
+ } else {
+ __ LoadIsolate(IP);
+ __ ldr(IP, Address(IP, Isolate::stack_limit_offset()));
+ }
__ cmp(SP, Operand(IP));
__ b(slow_path->entry_label(), LS);
if (compiler->CanOSRFunction() && in_loop()) {
@@ -6806,12 +6806,11 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
const Code& stub = Code::Handle(isolate,
- stub_code->GetAllocationStubForClass(cls()));
- const ExternalLabel label(stub.EntryPoint());
+ StubCode::GetAllocationStubForClass(cls()));
+ const StubEntry stub_entry(stub);
compiler->GenerateCall(token_pos(),
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs());
compiler->AddStubCallTarget(stub);
@@ -6821,9 +6820,8 @@
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
- compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
+ compiler->GenerateCall(
+ token_pos(), *StubCode::DebugStepCheck_entry(), stub_kind_, locs());
}
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 1f12744..9587767 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -56,11 +56,11 @@
if (value.IsRegister()) {
__ Push(value.reg());
} else if (value.IsConstant()) {
- __ PushObject(value.constant(), PP);
+ __ PushObject(value.constant());
} else {
ASSERT(value.IsStackSlot());
const intptr_t value_offset = value.ToStackSlotOffset();
- __ LoadFromOffset(TMP, value.base_reg(), value_offset, PP);
+ __ LoadFromOffset(TMP, value.base_reg(), value_offset);
__ Push(TMP);
}
}
@@ -98,13 +98,17 @@
(kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
ASSERT(fp_sp_dist <= 0);
__ sub(R2, SP, Operand(FP));
- __ CompareImmediate(R2, fp_sp_dist, PP);
+ __ CompareImmediate(R2, fp_sp_dist);
__ b(&stack_ok, EQ);
__ brk(0);
__ Bind(&stack_ok);
#endif
- __ LeaveDartFrame();
+ ASSERT(__ constant_pool_allowed());
+ __ LeaveDartFrame(); // Disallows constant pool use.
__ ret();
+ // This ReturnInstr may be emitted out of order by the optimizer. The next
+ // block may be a target expecting a properly set constant pool pointer.
+ __ set_constant_pool_allowed(true);
}
@@ -183,9 +187,9 @@
__ sub(result, result, Operand(1));
const int64_t val =
Smi::RawValue(true_value) - Smi::RawValue(false_value);
- __ AndImmediate(result, result, val, PP);
+ __ AndImmediate(result, result, val);
if (false_value != 0) {
- __ AddImmediate(result, result, Smi::RawValue(false_value), PP);
+ __ AddImmediate(result, result, Smi::RawValue(false_value));
}
}
}
@@ -209,17 +213,17 @@
const Array& arguments_descriptor =
Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
argument_names()));
- __ LoadObject(R4, arguments_descriptor, PP);
+ __ LoadObject(R4, arguments_descriptor);
// R4: Arguments descriptor.
// R0: Function.
ASSERT(locs()->in(0).reg() == R0);
- __ LoadFieldFromOffset(R2, R0, Function::instructions_offset(), PP);
+ __ LoadFieldFromOffset(R2, R0, Function::instructions_offset());
// R2: instructions.
// R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
- __ LoadImmediate(R5, 0, PP);
- __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP);
+ __ LoadImmediate(R5, 0);
+ __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag);
__ blr(R2);
compiler->RecordSafepoint(locs());
// Marks either the continuation point in unoptimized code or the
@@ -249,7 +253,7 @@
void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register result = locs()->out(0).reg();
- __ LoadFromOffset(result, FP, local().index() * kWordSize, PP);
+ __ LoadFromOffset(result, FP, local().index() * kWordSize);
}
@@ -266,7 +270,7 @@
const Register value = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
ASSERT(result == value); // Assert that register assignment is correct.
- __ StoreToOffset(value, FP, local().index() * kWordSize, PP);
+ __ StoreToOffset(value, FP, local().index() * kWordSize);
}
@@ -283,7 +287,7 @@
// The register allocator drops constant definitions that have no uses.
if (!locs()->out(0).IsInvalid()) {
const Register result = locs()->out(0).reg();
- __ LoadObject(result, value(), PP);
+ __ LoadObject(result, value());
}
}
@@ -309,13 +313,12 @@
__ veor(dst, dst, dst);
} else {
const VRegister dst = locs()->out(0).fpu_reg();
- __ LoadDImmediate(dst, Double::Cast(value()).value(), PP);
+ __ LoadDImmediate(dst, Double::Cast(value()).value());
}
break;
case kUnboxedInt32:
__ LoadImmediate(locs()->out(0).reg(),
- static_cast<int32_t>(Smi::Cast(value()).Value()),
- PP);
+ static_cast<int32_t>(Smi::Cast(value()).Value()));
break;
default:
UNREACHABLE();
@@ -362,13 +365,13 @@
Label done;
if (Isolate::Current()->flags().type_checks()) {
- __ CompareObject(reg, Bool::True(), PP);
+ __ CompareObject(reg, Bool::True());
__ b(&done, EQ);
- __ CompareObject(reg, Bool::False(), PP);
+ __ CompareObject(reg, Bool::False());
__ b(&done, EQ);
} else {
ASSERT(Isolate::Current()->flags().asserts());
- __ CompareObject(reg, Object::null_instance(), PP);
+ __ CompareObject(reg, Object::null_instance());
__ b(&done, NE);
}
@@ -456,10 +459,10 @@
Condition true_condition = TokenKindToSmiCondition(kind);
if (left.IsConstant()) {
- __ CompareObject(right.reg(), left.constant(), PP);
+ __ CompareObject(right.reg(), left.constant());
true_condition = FlipCondition(true_condition);
} else if (right.IsConstant()) {
- __ CompareObject(left.reg(), right.constant(), PP);
+ __ CompareObject(left.reg(), right.constant());
} else {
__ CompareRegisters(left.reg(), right.reg());
}
@@ -551,10 +554,10 @@
const Register result = locs()->out(0).reg();
Label done;
__ Bind(&is_false);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ b(&done);
__ Bind(&is_true);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -596,7 +599,7 @@
ASSERT(right.constant().IsSmi());
const int64_t imm =
reinterpret_cast<int64_t>(right.constant().raw());
- __ TestImmediate(left, imm, PP);
+ __ TestImmediate(left, imm);
} else {
__ tst(left, Operand(right.reg()));
}
@@ -647,13 +650,13 @@
bool result = data[1] == true_result;
__ tsti(val_reg, Immediate(kSmiTagMask));
__ b(result ? labels.true_label : labels.false_label, EQ);
- __ LoadClassId(cid_reg, val_reg, PP);
+ __ LoadClassId(cid_reg, val_reg);
for (intptr_t i = 2; i < data.length(); i += 2) {
const intptr_t test_cid = data[i];
ASSERT(test_cid != kSmiCid);
result = data[i + 1] == true_result;
- __ CompareImmediate(cid_reg, test_cid, PP);
+ __ CompareImmediate(cid_reg, test_cid);
__ b(result ? labels.true_label : labels.false_label, EQ);
}
// No match found, deoptimize or false.
@@ -686,10 +689,10 @@
// TODO(zra): instead of branching, use the csel instruction to get
// True or False into result.
__ Bind(&is_false);
- __ LoadObject(result_reg, Bool::False(), PP);
+ __ LoadObject(result_reg, Bool::False());
__ b(&done);
__ Bind(&is_true);
- __ LoadObject(result_reg, Bool::True(), PP);
+ __ LoadObject(result_reg, Bool::True());
__ Bind(&done);
}
@@ -746,10 +749,10 @@
const Register result = locs()->out(0).reg();
Label done;
__ Bind(&is_false);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ b(&done);
__ Bind(&is_true);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -777,13 +780,13 @@
const Register result = locs()->out(0).reg();
// Push the result place holder initialized to NULL.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
// Pass a pointer to the first argument in R2.
if (!function().HasOptionalParameters()) {
__ AddImmediate(R2, FP, (kParamEndSlotFromFp +
- function().NumParameters()) * kWordSize, PP);
+ function().NumParameters()) * kWordSize);
} else {
- __ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize, PP);
+ __ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize);
}
// Compute the effective address. When running under the simulator,
// this is a redirection address that forces the simulator to call
@@ -792,10 +795,9 @@
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
const bool is_leaf_call =
(argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel* stub_entry;
+ const StubEntry* stub_entry = NULL;
if (is_bootstrap_native() || is_leaf_call) {
- stub_entry = &stub_code->CallBootstrapCFunctionLabel();
+ stub_entry = StubCode::CallBootstrapCFunction_entry();
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kBootstrapNativeCall, function().NumParameters());
@@ -804,7 +806,7 @@
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = &stub_code->CallNativeCFunctionLabel();
+ stub_entry = StubCode::CallNativeCFunction_entry();
#if defined(USING_SIMULATOR)
if (!function().IsNativeAutoSetupScope()) {
entry = Simulator::RedirectExternalReference(
@@ -812,10 +814,10 @@
}
#endif
}
- __ LoadImmediate(R5, entry, PP);
- __ LoadImmediate(R1, argc_tag, PP);
+ __ LoadImmediate(R5, entry);
+ __ LoadImmediate(R1, argc_tag);
compiler->GenerateCall(token_pos(),
- stub_entry,
+ *stub_entry,
RawPcDescriptors::kOther,
locs());
__ Pop(result);
@@ -834,12 +836,13 @@
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(compiler->is_optimizing());
const Register char_code = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
__ LoadImmediate(
- result, reinterpret_cast<uword>(Symbols::PredefinedAddress()), PP);
+ result, reinterpret_cast<uword>(Symbols::PredefinedAddress()));
__ AddImmediate(
- result, result, Symbols::kNullCharCodeSymbolOffset * kWordSize, PP);
+ result, result, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ SmiUntag(TMP, char_code); // Untag to use scaled adress mode.
__ ldr(result, Address(result, TMP, UXTX, Address::Scaled));
}
@@ -859,10 +862,10 @@
ASSERT(cid_ == kOneByteStringCid);
const Register str = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ LoadFieldFromOffset(result, str, String::length_offset(), PP);
+ __ LoadFieldFromOffset(result, str, String::length_offset());
__ ldr(TMP, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte);
- __ CompareImmediate(result, Smi::RawValue(1), PP);
- __ LoadImmediate(result, -1, PP);
+ __ CompareImmediate(result, Smi::RawValue(1));
+ __ LoadImmediate(result, -1);
__ csel(result, TMP, result, EQ);
__ SmiTag(result);
}
@@ -910,10 +913,10 @@
const Register obj = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
if (object()->definition()->representation() == kUntagged) {
- __ LoadFromOffset(result, obj, offset(), PP);
+ __ LoadFromOffset(result, obj, offset());
} else {
ASSERT(object()->definition()->representation() == kTagged);
- __ LoadFieldFromOffset(result, obj, offset(), PP);
+ __ LoadFieldFromOffset(result, obj, offset());
}
}
@@ -934,10 +937,10 @@
static const intptr_t kSmiCidSource =
static_cast<intptr_t>(kSmiCid) << RawObject::kClassIdTagPos;
- __ LoadImmediate(TMP, reinterpret_cast<int64_t>(&kSmiCidSource) + 1, PP);
+ __ LoadImmediate(TMP, reinterpret_cast<int64_t>(&kSmiCidSource) + 1);
__ tsti(object, Immediate(kSmiTagMask));
__ csel(TMP, TMP, object, EQ);
- __ LoadClassId(result, TMP, PP);
+ __ LoadClassId(result, TMP);
__ SmiTag(result);
}
@@ -1311,7 +1314,7 @@
case kOneByteStringCid: {
if (locs()->in(2).IsConstant()) {
const Smi& constant = Smi::Cast(locs()->in(2).constant());
- __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()), PP);
+ __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()));
__ str(TMP, element_address, kUnsignedByte);
} else {
const Register value = locs()->in(2).reg();
@@ -1331,11 +1334,11 @@
} else if (value < 0) {
value = 0;
}
- __ LoadImmediate(TMP, static_cast<int8_t>(value), PP);
+ __ LoadImmediate(TMP, static_cast<int8_t>(value));
__ str(TMP, element_address, kUnsignedByte);
} else {
const Register value = locs()->in(2).reg();
- __ CompareImmediate(value, 0x1FE, PP); // Smi value and smi 0xFF.
+ __ CompareImmediate(value, 0x1FE); // Smi value and smi 0xFF.
// Clamp to 0x00 or 0xFF respectively.
__ csetm(TMP, GT); // TMP = value > 0x1FE ? -1 : 0.
__ csel(TMP, value, TMP, LS); // TMP = value in range ? value : TMP.
@@ -1386,7 +1389,7 @@
Label* value_is_smi = NULL) {
Label done;
if (value_is_smi == NULL) {
- __ LoadImmediate(value_cid_reg, kSmiCid, PP);
+ __ LoadImmediate(value_cid_reg, kSmiCid);
}
__ tsti(value_reg, Immediate(kSmiTagMask));
if (value_is_smi == NULL) {
@@ -1394,7 +1397,7 @@
} else {
__ b(value_is_smi, EQ);
}
- __ LoadClassId(value_cid_reg, value_reg, PP);
+ __ LoadClassId(value_cid_reg, value_reg);
__ Bind(&done);
}
@@ -1469,7 +1472,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
FieldAddress field_cid_operand(
field_reg, Field::guarded_cid_offset(), kUnsignedWord);
@@ -1486,11 +1489,11 @@
__ CompareRegisters(value_cid_reg, TMP);
} else if (value_cid == kNullCid) {
__ ldr(value_cid_reg, field_nullability_operand, kUnsignedWord);
- __ CompareImmediate(value_cid_reg, value_cid, PP);
+ __ CompareImmediate(value_cid_reg, value_cid);
} else {
Label skip_length_check;
__ ldr(value_cid_reg, field_cid_operand, kUnsignedWord);
- __ CompareImmediate(value_cid_reg, value_cid, PP);
+ __ CompareImmediate(value_cid_reg, value_cid);
}
__ b(&ok, EQ);
@@ -1504,14 +1507,14 @@
// Uninitialized field can be handled inline. Check if the
// field is still unitialized.
__ ldr(TMP, field_cid_operand, kUnsignedWord);
- __ CompareImmediate(TMP, kIllegalCid, PP);
+ __ CompareImmediate(TMP, kIllegalCid);
__ b(fail, NE);
if (value_cid == kDynamicCid) {
__ str(value_cid_reg, field_cid_operand, kUnsignedWord);
__ str(value_cid_reg, field_nullability_operand, kUnsignedWord);
} else {
- __ LoadImmediate(TMP, value_cid, PP);
+ __ LoadImmediate(TMP, value_cid);
__ str(TMP, field_cid_operand, kUnsignedWord);
__ str(TMP, field_nullability_operand, kUnsignedWord);
}
@@ -1527,8 +1530,8 @@
__ Bind(fail);
__ LoadFieldFromOffset(
- TMP, field_reg, Field::guarded_cid_offset(), PP, kUnsignedWord);
- __ CompareImmediate(TMP, kDynamicCid, PP);
+ TMP, field_reg, Field::guarded_cid_offset(), kUnsignedWord);
+ __ CompareImmediate(TMP, kDynamicCid);
__ b(&ok, EQ);
__ Push(field_reg);
@@ -1547,13 +1550,13 @@
if (field_cid != kSmiCid) {
__ b(fail, EQ);
- __ LoadClassId(value_cid_reg, value_reg, PP);
- __ CompareImmediate(value_cid_reg, field_cid, PP);
+ __ LoadClassId(value_cid_reg, value_reg);
+ __ CompareImmediate(value_cid_reg, field_cid);
}
if (field().is_nullable() && (field_cid != kNullCid)) {
__ b(&ok, EQ);
- __ CompareObject(value_reg, Object::null_object(), PP);
+ __ CompareObject(value_reg, Object::null_object());
}
__ b(fail, NE);
@@ -1609,7 +1612,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
__ ldr(offset_reg,
FieldAddress(field_reg,
@@ -1648,7 +1651,7 @@
__ ldr(TMP, FieldAddress(value_reg,
field().guarded_list_length_in_object_offset()));
- __ CompareImmediate(TMP, Smi::RawValue(field().guarded_list_length()), PP);
+ __ CompareImmediate(TMP, Smi::RawValue(field().guarded_list_length()));
__ b(deopt, NE);
}
}
@@ -1665,7 +1668,6 @@
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
@@ -1674,8 +1676,8 @@
}
__ Bind(entry_label());
const Code& stub =
- Code::Handle(isolate, stub_code->GetAllocationStubForClass(cls_));
- const ExternalLabel label(stub.EntryPoint());
+ Code::Handle(isolate, StubCode::GetAllocationStubForClass(cls_));
+ const StubEntry stub_entry(stub);
LocationSummary* locs = instruction_->locs();
@@ -1683,9 +1685,10 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs);
+ compiler->AddStubCallTarget(stub);
__ mov(result_, R0);
compiler->RestoreLiveRegisters(locs);
__ b(exit_label());
@@ -1697,21 +1700,13 @@
Register result,
Register temp) {
if (compiler->intrinsic_mode()) {
- __ TryAllocate(cls,
- compiler->intrinsic_slow_path_label(),
- result,
- temp,
- PP);
+ __ TryAllocate(cls, compiler->intrinsic_slow_path_label(), result, temp);
} else {
BoxAllocationSlowPath* slow_path =
new BoxAllocationSlowPath(instruction, cls, result);
compiler->AddSlowPathCode(slow_path);
- __ TryAllocate(cls,
- slow_path->entry_label(),
- result,
- temp,
- PP);
+ __ TryAllocate(cls, slow_path->entry_label(), result, temp);
__ Bind(slow_path->exit_label());
}
}
@@ -1731,13 +1726,13 @@
intptr_t offset,
Register temp) {
Label done;
- __ LoadFieldFromOffset(box_reg, instance_reg, offset, PP);
- __ CompareObject(box_reg, Object::null_object(), PP);
+ __ LoadFieldFromOffset(box_reg, instance_reg, offset);
+ __ CompareObject(box_reg, Object::null_object());
__ b(&done, NE);
BoxAllocationSlowPath::Allocate(
compiler, instruction, cls, box_reg, temp);
__ mov(temp, box_reg);
- __ StoreIntoObjectOffset(instance_reg, offset, temp, PP);
+ __ StoreIntoObjectOffset(instance_reg, offset, temp);
__ Bind(&done);
}
@@ -1805,22 +1800,22 @@
BoxAllocationSlowPath::Allocate(compiler, this, *cls, temp, temp2);
__ mov(temp2, temp);
- __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2, PP);
+ __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2);
} else {
- __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_, PP);
+ __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_);
}
switch (cid) {
case kDoubleCid:
__ Comment("UnboxedDoubleStoreInstanceFieldInstr");
- __ StoreDFieldToOffset(value, temp, Double::value_offset(), PP);
+ __ StoreDFieldToOffset(value, temp, Double::value_offset());
break;
case kFloat32x4Cid:
__ Comment("UnboxedFloat32x4StoreInstanceFieldInstr");
- __ StoreQFieldToOffset(value, temp, Float32x4::value_offset(), PP);
+ __ StoreQFieldToOffset(value, temp, Float32x4::value_offset());
break;
case kFloat64x2Cid:
__ Comment("UnboxedFloat64x2StoreInstanceFieldInstr");
- __ StoreQFieldToOffset(value, temp, Float64x2::value_offset(), PP);
+ __ StoreQFieldToOffset(value, temp, Float64x2::value_offset());
break;
default:
UNREACHABLE();
@@ -1845,32 +1840,32 @@
Label store_float32x4;
Label store_float64x2;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP);
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()));
- __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(), PP,
+ __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(),
kUnsignedWord);
- __ CompareImmediate(temp2, kNullCid, PP);
+ __ CompareImmediate(temp2, kNullCid);
__ b(&store_pointer, EQ);
__ LoadFromOffset(
temp2, temp, Field::kind_bits_offset() - kHeapObjectTag,
- PP, kUnsignedByte);
+ kUnsignedByte);
__ tsti(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
__ b(&store_pointer, EQ);
- __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP,
+ __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(),
kUnsignedWord);
- __ CompareImmediate(temp2, kDoubleCid, PP);
+ __ CompareImmediate(temp2, kDoubleCid);
__ b(&store_double, EQ);
- __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP,
+ __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(),
kUnsignedWord);
- __ CompareImmediate(temp2, kFloat32x4Cid, PP);
+ __ CompareImmediate(temp2, kFloat32x4Cid);
__ b(&store_float32x4, EQ);
- __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP,
+ __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(),
kUnsignedWord);
- __ CompareImmediate(temp2, kFloat64x2Cid, PP);
+ __ CompareImmediate(temp2, kFloat64x2Cid);
__ b(&store_float64x2, EQ);
// Fall through.
@@ -1890,8 +1885,8 @@
instance_reg,
offset_in_bytes_,
temp2);
- __ LoadDFieldFromOffset(VTMP, value_reg, Double::value_offset(), PP);
- __ StoreDFieldToOffset(VTMP, temp, Double::value_offset(), PP);
+ __ LoadDFieldFromOffset(VTMP, value_reg, Double::value_offset());
+ __ StoreDFieldToOffset(VTMP, temp, Double::value_offset());
__ b(&skip_store);
}
@@ -1904,8 +1899,8 @@
instance_reg,
offset_in_bytes_,
temp2);
- __ LoadQFieldFromOffset(VTMP, value_reg, Float32x4::value_offset(), PP);
- __ StoreQFieldToOffset(VTMP, temp, Float32x4::value_offset(), PP);
+ __ LoadQFieldFromOffset(VTMP, value_reg, Float32x4::value_offset());
+ __ StoreQFieldToOffset(VTMP, temp, Float32x4::value_offset());
__ b(&skip_store);
}
@@ -1918,8 +1913,8 @@
instance_reg,
offset_in_bytes_,
temp2);
- __ LoadQFieldFromOffset(VTMP, value_reg, Float64x2::value_offset(), PP);
- __ StoreQFieldToOffset(VTMP, temp, Float64x2::value_offset(), PP);
+ __ LoadQFieldFromOffset(VTMP, value_reg, Float64x2::value_offset());
+ __ StoreQFieldToOffset(VTMP, temp, Float64x2::value_offset());
__ b(&skip_store);
}
@@ -1929,21 +1924,15 @@
if (ShouldEmitStoreBarrier()) {
const Register value_reg = locs()->in(1).reg();
__ StoreIntoObjectOffset(
- instance_reg, offset_in_bytes_, value_reg, PP, CanValueBeSmi());
+ instance_reg, offset_in_bytes_, value_reg, CanValueBeSmi());
} else {
if (locs()->in(1).IsConstant()) {
__ StoreIntoObjectOffsetNoBarrier(
- instance_reg,
- offset_in_bytes_,
- locs()->in(1).constant(),
- PP);
+ instance_reg, offset_in_bytes_, locs()->in(1).constant());
} else {
const Register value_reg = locs()->in(1).reg();
__ StoreIntoObjectOffsetNoBarrier(
- instance_reg,
- offset_in_bytes_,
- value_reg,
- PP);
+ instance_reg, offset_in_bytes_, value_reg);
}
}
__ Bind(&skip_store);
@@ -1970,7 +1959,7 @@
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register field = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ LoadFieldFromOffset(result, field, Field::value_offset(), PP);
+ __ LoadFieldFromOffset(result, field, Field::value_offset());
}
@@ -1989,12 +1978,12 @@
const Register value = locs()->in(0).reg();
const Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field(), PP);
+ __ LoadObject(temp, field());
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObjectOffset(
- temp, Field::value_offset(), value, PP, CanValueBeSmi());
+ temp, Field::value_offset(), value, CanValueBeSmi());
} else {
- __ StoreIntoObjectOffsetNoBarrier(temp, Field::value_offset(), value, PP);
+ __ StoreIntoObjectOffsetNoBarrier(temp, Field::value_offset(), value);
}
}
@@ -2077,8 +2066,8 @@
// R6: null
if (num_elements > 0) {
const intptr_t array_size = instance_size - sizeof(RawArray);
- __ LoadObject(R6, Object::null_object(), PP);
- __ AddImmediate(R8, R0, sizeof(RawArray) - kHeapObjectTag, PP);
+ __ LoadObject(R6, Object::null_object());
+ __ AddImmediate(R8, R0, sizeof(RawArray) - kHeapObjectTag);
if (array_size < (kInlineArraySize * kWordSize)) {
intptr_t current_offset = 0;
while (current_offset < array_size) {
@@ -2091,7 +2080,7 @@
__ CompareRegisters(R8, R3);
__ b(&end_loop, CS);
__ str(R6, Address(R8));
- __ AddImmediate(R8, R8, kWordSize, kNoPP);
+ __ AddImmediate(R8, R8, kWordSize);
__ b(&init_loop);
__ Bind(&end_loop);
}
@@ -2116,7 +2105,7 @@
Label slow_path, done;
InlineArrayAllocation(compiler, length, &slow_path, &done);
__ Bind(&slow_path);
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ Push(kLengthReg); // length.
__ Push(kElemTypeReg);
compiler->GenerateRuntimeCall(token_pos(),
@@ -2130,15 +2119,10 @@
return;
}
}
- Isolate* isolate = compiler->isolate();
- const Code& stub = Code::Handle(
- isolate, isolate->stub_code()->GetAllocateArrayStub());
- const ExternalLabel label(stub.EntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
locs());
- compiler->AddStubCallTarget(stub);
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2173,18 +2157,18 @@
if (IsUnboxedLoad() && compiler->is_optimizing()) {
const VRegister result = locs()->out(0).fpu_reg();
const Register temp = locs()->temp(0).reg();
- __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP);
+ __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes());
const intptr_t cid = field()->UnboxedFieldCid();
switch (cid) {
case kDoubleCid:
__ Comment("UnboxedDoubleLoadFieldInstr");
- __ LoadDFieldFromOffset(result, temp, Double::value_offset(), PP);
+ __ LoadDFieldFromOffset(result, temp, Double::value_offset());
break;
case kFloat32x4Cid:
- __ LoadQFieldFromOffset(result, temp, Float32x4::value_offset(), PP);
+ __ LoadQFieldFromOffset(result, temp, Float32x4::value_offset());
break;
case kFloat64x2Cid:
- __ LoadQFieldFromOffset(result, temp, Float64x2::value_offset(), PP);
+ __ LoadQFieldFromOffset(result, temp, Float64x2::value_offset());
break;
default:
UNREACHABLE();
@@ -2202,7 +2186,7 @@
Label load_float32x4;
Label load_float64x2;
- __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()), PP);
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
FieldAddress field_cid_operand(
result_reg, Field::guarded_cid_offset(), kUnsignedWord);
@@ -2210,19 +2194,19 @@
result_reg, Field::is_nullable_offset(), kUnsignedWord);
__ ldr(temp, field_nullability_operand, kUnsignedWord);
- __ CompareImmediate(temp, kNullCid, PP);
+ __ CompareImmediate(temp, kNullCid);
__ b(&load_pointer, EQ);
__ ldr(temp, field_cid_operand, kUnsignedWord);
- __ CompareImmediate(temp, kDoubleCid, PP);
+ __ CompareImmediate(temp, kDoubleCid);
__ b(&load_double, EQ);
__ ldr(temp, field_cid_operand, kUnsignedWord);
- __ CompareImmediate(temp, kFloat32x4Cid, PP);
+ __ CompareImmediate(temp, kFloat32x4Cid);
__ b(&load_float32x4, EQ);
__ ldr(temp, field_cid_operand, kUnsignedWord);
- __ CompareImmediate(temp, kFloat64x2Cid, PP);
+ __ CompareImmediate(temp, kFloat64x2Cid);
__ b(&load_float64x2, EQ);
// Fall through.
@@ -2239,9 +2223,9 @@
compiler->double_class(),
result_reg,
temp);
- __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP);
- __ LoadDFieldFromOffset(VTMP, temp, Double::value_offset(), PP);
- __ StoreDFieldToOffset(VTMP, result_reg, Double::value_offset(), PP);
+ __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes());
+ __ LoadDFieldFromOffset(VTMP, temp, Double::value_offset());
+ __ StoreDFieldToOffset(VTMP, result_reg, Double::value_offset());
__ b(&done);
}
@@ -2252,9 +2236,9 @@
compiler->float32x4_class(),
result_reg,
temp);
- __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP);
- __ LoadQFieldFromOffset(VTMP, temp, Float32x4::value_offset(), PP);
- __ StoreQFieldToOffset(VTMP, result_reg, Float32x4::value_offset(), PP);
+ __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes());
+ __ LoadQFieldFromOffset(VTMP, temp, Float32x4::value_offset());
+ __ StoreQFieldToOffset(VTMP, result_reg, Float32x4::value_offset());
__ b(&done);
}
@@ -2265,15 +2249,15 @@
compiler->float64x2_class(),
result_reg,
temp);
- __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP);
- __ LoadQFieldFromOffset(VTMP, temp, Float64x2::value_offset(), PP);
- __ StoreQFieldToOffset(VTMP, result_reg, Float64x2::value_offset(), PP);
+ __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes());
+ __ LoadQFieldFromOffset(VTMP, temp, Float64x2::value_offset());
+ __ StoreQFieldToOffset(VTMP, result_reg, Float64x2::value_offset());
__ b(&done);
}
__ Bind(&load_pointer);
}
- __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes(), PP);
+ __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes());
__ Bind(&done);
}
@@ -2296,8 +2280,8 @@
// 'instantiator_reg' is the instantiator TypeArguments object (or null).
// A runtime call to instantiate the type is required.
- __ PushObject(Object::null_object(), PP); // Make room for the result.
- __ PushObject(type(), PP);
+ __ PushObject(Object::null_object()); // Make room for the result.
+ __ PushObject(type());
__ Push(instantiator_reg); // Push instantiator type arguments.
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2339,33 +2323,33 @@
Label type_arguments_instantiated;
const intptr_t len = type_arguments().Length();
if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ CompareObject(instantiator_reg, Object::null_object(), PP);
+ __ CompareObject(instantiator_reg, Object::null_object());
__ b(&type_arguments_instantiated, EQ);
}
- __ LoadObject(R2, type_arguments(), PP);
- __ LoadFieldFromOffset(R2, R2, TypeArguments::instantiations_offset(), PP);
- __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag, PP);
+ __ LoadObject(R2, type_arguments());
+ __ LoadFieldFromOffset(R2, R2, TypeArguments::instantiations_offset());
+ __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag);
// The instantiations cache is initialized with Object::zero_array() and is
// therefore guaranteed to contain kNoInstantiator. No length check needed.
Label loop, found, slow_case;
__ Bind(&loop);
- __ LoadFromOffset(R1, R2, 0 * kWordSize, PP); // Cached instantiator.
+ __ LoadFromOffset(R1, R2, 0 * kWordSize); // Cached instantiator.
__ CompareRegisters(R1, R0);
__ b(&found, EQ);
- __ AddImmediate(R2, R2, 2 * kWordSize, PP);
- __ CompareImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator), PP);
+ __ AddImmediate(R2, R2, 2 * kWordSize);
+ __ CompareImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator));
__ b(&loop, NE);
__ b(&slow_case);
__ Bind(&found);
- __ LoadFromOffset(R0, R2, 1 * kWordSize, PP); // Cached instantiated args.
+ __ LoadFromOffset(R0, R2, 1 * kWordSize); // Cached instantiated args.
__ b(&type_arguments_instantiated);
__ Bind(&slow_case);
// Instantiate non-null type arguments.
// A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::null_object(), PP); // Make room for the result.
- __ PushObject(type_arguments(), PP);
+ __ PushObject(Object::null_object()); // Make room for the result.
+ __ PushObject(type_arguments());
__ Push(instantiator_reg); // Push instantiator type arguments.
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2409,11 +2393,9 @@
compiler->SaveLiveRegisters(locs);
- __ LoadImmediate(R1, instruction_->num_context_variables(), PP);
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
+ __ LoadImmediate(R1, instruction_->num_context_variables());
compiler->GenerateCall(instruction_->token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs);
ASSERT(instruction_->locs()->out(0).reg() == R0);
@@ -2445,7 +2427,7 @@
temp2);
// Setup up number of context variables field.
- __ LoadImmediate(temp0, num_context_variables(), PP);
+ __ LoadImmediate(temp0, num_context_variables());
__ str(temp0, FieldAddress(result, Context::num_variables_offset()));
__ Bind(slow_path->exit_label());
@@ -2468,11 +2450,9 @@
ASSERT(locs()->temp(0).reg() == R1);
ASSERT(locs()->out(0).reg() == R0);
- __ LoadImmediate(R1, num_context_variables(), PP);
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
+ __ LoadImmediate(R1, num_context_variables());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs());
}
@@ -2495,14 +2475,14 @@
Label call_runtime, no_call;
__ ldr(temp, FieldAddress(field, Field::value_offset()));
- __ CompareObject(temp, Object::sentinel(), PP);
+ __ CompareObject(temp, Object::sentinel());
__ b(&call_runtime, EQ);
- __ CompareObject(temp, Object::transition_sentinel(), PP);
+ __ CompareObject(temp, Object::transition_sentinel());
__ b(&no_call, NE);
__ Bind(&call_runtime);
- __ PushObject(Object::null_object(), PP); // Make room for (unused) result.
+ __ PushObject(Object::null_object()); // Make room for (unused) result.
__ Push(field);
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2530,7 +2510,7 @@
const Register context_value = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ Push(context_value);
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2558,7 +2538,7 @@
needs_stacktrace());
// Restore the pool pointer.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -2569,14 +2549,14 @@
const intptr_t fp_sp_dist =
(kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
ASSERT(fp_sp_dist <= 0);
- __ AddImmediate(SP, FP, fp_sp_dist, PP);
+ __ AddImmediate(SP, FP, fp_sp_dist);
// Restore stack and initialize the two exception variables:
// exception and stack trace variables.
__ StoreToOffset(kExceptionObjectReg,
- FP, exception_var().index() * kWordSize, PP);
+ FP, exception_var().index() * kWordSize);
__ StoreToOffset(kStackTraceObjectReg,
- FP, stacktrace_var().index() * kWordSize, PP);
+ FP, stacktrace_var().index() * kWordSize);
}
@@ -2602,8 +2582,8 @@
const Register value = instruction_->locs()->temp(0).reg();
__ Comment("CheckStackOverflowSlowPathOsr");
__ Bind(osr_entry_label());
- __ LoadImmediate(TMP, flags_address, PP);
- __ LoadImmediate(value, Isolate::kOsrRequest, PP);
+ __ LoadImmediate(TMP, flags_address);
+ __ LoadImmediate(value, Isolate::kOsrRequest);
__ str(value, Address(TMP));
}
__ Comment("CheckStackOverflowSlowPath");
@@ -2646,8 +2626,13 @@
CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
compiler->AddSlowPathCode(slow_path);
- __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address(), PP);
- __ ldr(TMP, Address(TMP));
+ if (compiler->is_optimizing()) {
+ __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address());
+ __ ldr(TMP, Address(TMP));
+ } else {
+ __ LoadIsolate(TMP);
+ __ ldr(TMP, Address(TMP, Isolate::stack_limit_offset()));
+ }
__ CompareRegisters(SP, TMP);
__ b(slow_path->entry_label(), LS);
if (compiler->CanOSRFunction() && in_loop()) {
@@ -2655,12 +2640,12 @@
// In unoptimized code check the usage counter to trigger OSR at loop
// stack checks. Use progressively higher thresholds for more deeply
// nested loops to attempt to hit outer loops with OSR when possible.
- __ LoadObject(temp, compiler->parsed_function().function(), PP);
+ __ LoadObject(temp, compiler->parsed_function().function());
intptr_t threshold =
FLAG_optimization_counter_threshold * (loop_depth() + 1);
__ LoadFieldFromOffset(
- temp, temp, Function::usage_counter_offset(), PP, kWord);
- __ CompareImmediate(temp, threshold, PP);
+ temp, temp, Function::usage_counter_offset(), kWord);
+ __ CompareImmediate(temp, threshold);
__ b(slow_path->osr_entry_label(), GE);
}
if (compiler->ForceSlowPathForStackOverflow()) {
@@ -2676,7 +2661,7 @@
Register result) {
if (!RangeUtils::IsWithin(range, -0x20000000000000LL, 0x20000000000000LL)) {
ASSERT(overflow != NULL);
- __ LoadImmediate(TMP, 0x20000000000000LL, PP);
+ __ LoadImmediate(TMP, 0x20000000000000LL);
__ add(TMP2, result, Operand(TMP));
__ cmp(TMP2, Operand(TMP, LSL, 1));
__ b(overflow, HI);
@@ -2733,7 +2718,7 @@
!RangeUtils::IsWithin(right_range, 0, max_right - 1);
if (right_needs_check) {
__ CompareImmediate(right,
- reinterpret_cast<int64_t>(Smi::New(max_right)), PP);
+ reinterpret_cast<int64_t>(Smi::New(max_right)));
__ b(deopt, CS);
}
__ SmiUntag(TMP, right);
@@ -2758,7 +2743,7 @@
}
__ CompareImmediate(
- right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP);
+ right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)));
__ csel(result, ZR, result, CS);
__ SmiUntag(TMP, right);
__ lslv(TMP, left, TMP);
@@ -2771,7 +2756,7 @@
if (right_needs_check) {
ASSERT(shift_left->CanDeoptimize());
__ CompareImmediate(
- right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP);
+ right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)));
__ b(deopt, CS);
}
// Left is not a constant.
@@ -2850,20 +2835,20 @@
switch (op_kind()) {
case Token::kADD: {
if (deopt == NULL) {
- __ AddImmediate(result, left, imm, PP);
+ __ AddImmediate(result, left, imm);
} else {
- __ AddImmediateSetFlags(result, left, imm, PP);
+ __ AddImmediateSetFlags(result, left, imm);
__ b(deopt, VS);
}
break;
}
case Token::kSUB: {
if (deopt == NULL) {
- __ AddImmediate(result, left, -imm, PP);
+ __ AddImmediate(result, left, -imm);
} else {
// Negating imm and using AddImmediateSetFlags would not detect the
// overflow when imm == kMinInt64.
- __ SubImmediateSetFlags(result, left, imm, PP);
+ __ SubImmediateSetFlags(result, left, imm);
__ b(deopt, VS);
}
break;
@@ -2871,7 +2856,7 @@
case Token::kMUL: {
// Keep left value tagged and untag right value.
const intptr_t value = Smi::Cast(constant).Value();
- __ LoadImmediate(TMP, value, PP);
+ __ LoadImmediate(TMP, value);
__ mul(result, left, TMP);
if (deopt != NULL) {
__ smulh(TMP, left, TMP);
@@ -2901,15 +2886,15 @@
}
case Token::kBIT_AND:
// No overflow check.
- __ AndImmediate(result, left, imm, PP);
+ __ AndImmediate(result, left, imm);
break;
case Token::kBIT_OR:
// No overflow check.
- __ OrImmediate(result, left, imm, PP);
+ __ OrImmediate(result, left, imm);
break;
case Token::kBIT_XOR:
// No overflow check.
- __ XorImmediate(result, left, imm, PP);
+ __ XorImmediate(result, left, imm);
break;
case Token::kSHR: {
// Asr operation masks the count to 6 bits.
@@ -2993,7 +2978,7 @@
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(result, 0x4000000000000000LL, kNoPP);
+ __ CompareImmediate(result, 0x4000000000000000LL);
__ b(deopt, EQ);
__ SmiTag(result);
break;
@@ -3042,7 +3027,7 @@
const intptr_t kCountLimit = 0x3F;
if ((right_range == NULL) ||
!right_range->OnlyLessThanOrEqualTo(kCountLimit)) {
- __ LoadImmediate(TMP2, kCountLimit, PP);
+ __ LoadImmediate(TMP2, kCountLimit);
__ CompareRegisters(TMP, TMP2);
__ csel(TMP, TMP2, TMP, GT);
}
@@ -3137,12 +3122,12 @@
switch (from_representation()) {
case kUnboxedDouble:
- __ StoreDFieldToOffset(value, out_reg, ValueOffset(), PP);
+ __ StoreDFieldToOffset(value, out_reg, ValueOffset());
break;
case kUnboxedFloat32x4:
case kUnboxedFloat64x2:
case kUnboxedInt32x4:
- __ StoreQFieldToOffset(value, out_reg, ValueOffset(), PP);
+ __ StoreQFieldToOffset(value, out_reg, ValueOffset());
break;
default:
UNREACHABLE();
@@ -3174,7 +3159,7 @@
case kUnboxedDouble: {
const VRegister result = locs()->out(0).fpu_reg();
- __ LoadDFieldFromOffset(result, box, ValueOffset(), PP);
+ __ LoadDFieldFromOffset(result, box, ValueOffset());
break;
}
@@ -3182,7 +3167,7 @@
case kUnboxedFloat64x2:
case kUnboxedInt32x4: {
const VRegister result = locs()->out(0).fpu_reg();
- __ LoadQFieldFromOffset(result, box, ValueOffset(), PP);
+ __ LoadQFieldFromOffset(result, box, ValueOffset());
break;
}
@@ -3232,12 +3217,12 @@
if ((value()->Type()->ToNullableCid() == box_cid) &&
value()->Type()->is_nullable()) {
- __ CompareObject(box, Object::null_object(), PP);
+ __ CompareObject(box, Object::null_object());
__ b(deopt, EQ);
} else {
__ tsti(box, Immediate(kSmiTagMask));
__ b(CanConvertSmi() ? &is_smi : deopt, EQ);
- __ CompareClassId(box, box_cid, PP);
+ __ CompareClassId(box, box_cid);
__ b(deopt, NE);
}
@@ -3313,7 +3298,7 @@
if (value_cid == kSmiCid) {
__ SmiUntag(out, value);
} else if (value_cid == kMintCid) {
- __ LoadFieldFromOffset(out, value, Mint::value_offset(), PP);
+ __ LoadFieldFromOffset(out, value, Mint::value_offset());
} else if (!CanDeoptimize()) {
// Type information is not conclusive, but range analysis found
// the value to be in int64 range. Therefore it must be a smi
@@ -3321,18 +3306,18 @@
ASSERT(is_truncating());
Label done;
__ SmiUntag(out, value);
- __ TestImmediate(value, kSmiTagMask, PP);
+ __ TestImmediate(value, kSmiTagMask);
__ b(&done, EQ);
- __ LoadFieldFromOffset(out, value, Mint::value_offset(), PP);
+ __ LoadFieldFromOffset(out, value, Mint::value_offset());
__ Bind(&done);
} else {
Label done;
__ SmiUntag(out, value);
- __ TestImmediate(value, kSmiTagMask, PP);
+ __ TestImmediate(value, kSmiTagMask);
__ b(&done, EQ);
- __ CompareClassId(value, kMintCid, PP);
+ __ CompareClassId(value, kMintCid);
__ b(deopt, NE);
- __ LoadFieldFromOffset(out, value, Mint::value_offset(), PP);
+ __ LoadFieldFromOffset(out, value, Mint::value_offset());
__ Bind(&done);
}
@@ -4168,25 +4153,25 @@
const VRegister result = locs()->out(0).fpu_reg();
__ veor(result, result, result);
- __ LoadImmediate(temp, 0xffffffff, PP);
- __ LoadObject(TMP2, Bool::True(), PP);
+ __ LoadImmediate(temp, 0xffffffff);
+ __ LoadObject(TMP2, Bool::True());
- // __ CompareObject(v0, Bool::True(), PP);
+ // __ CompareObject(v0, Bool::True());
__ CompareRegisters(v0, TMP2);
__ csel(TMP, temp, ZR, EQ);
__ vinsw(result, 0, TMP);
- // __ CompareObject(v1, Bool::True(), PP);
+ // __ CompareObject(v1, Bool::True());
__ CompareRegisters(v1, TMP2);
__ csel(TMP, temp, ZR, EQ);
__ vinsw(result, 1, TMP);
- // __ CompareObject(v2, Bool::True(), PP);
+ // __ CompareObject(v2, Bool::True());
__ CompareRegisters(v2, TMP2);
__ csel(TMP, temp, ZR, EQ);
__ vinsw(result, 2, TMP);
- // __ CompareObject(v3, Bool::True(), PP);
+ // __ CompareObject(v3, Bool::True());
__ CompareRegisters(v3, TMP2);
__ csel(TMP, temp, ZR, EQ);
__ vinsw(result, 3, TMP);
@@ -4226,8 +4211,8 @@
}
__ tst(result, Operand(result));
- __ LoadObject(result, Bool::True(), PP);
- __ LoadObject(TMP, Bool::False(), PP);
+ __ LoadObject(result, Bool::True());
+ __ LoadObject(TMP, Bool::False());
__ csel(result, TMP, result, EQ);
}
@@ -4289,8 +4274,8 @@
__ vmov(result, mask);
}
- __ CompareObject(flag, Bool::True(), PP);
- __ LoadImmediate(TMP, 0xffffffff, PP);
+ __ CompareObject(flag, Bool::True());
+ __ LoadImmediate(TMP, 0xffffffff);
__ csel(TMP, TMP, ZR, EQ);
switch (op_kind()) {
case MethodRecognizer::kInt32x4WithFlagX:
@@ -4469,7 +4454,7 @@
__ b(&done);
__ Bind(&returns_nan);
- __ LoadDImmediate(result, NAN, PP);
+ __ LoadDImmediate(result, NAN);
__ b(&done);
__ Bind(&are_equal);
@@ -4480,7 +4465,7 @@
// - max -> left is negative ? right : left
// Check the sign bit.
__ fmovrd(TMP, left); // Sign bit is in bit 63 of TMP.
- __ CompareImmediate(TMP, 0, PP);
+ __ CompareImmediate(TMP, 0);
if (is_min) {
ASSERT(left == result);
__ b(&done, LT);
@@ -4633,7 +4618,7 @@
const Register value_obj = locs()->in(0).reg();
ASSERT(result == R0);
ASSERT(result != value_obj);
- __ LoadDFieldFromOffset(VTMP, value_obj, Double::value_offset(), PP);
+ __ LoadDFieldFromOffset(VTMP, value_obj, Double::value_offset());
Label do_call, done;
// First check for NaN. Checking for minint after the conversion doesn't work
@@ -4645,7 +4630,7 @@
// Overflow is signaled with minint.
// Check for overflow and that it fits into Smi.
- __ CompareImmediate(result, 0xC000000000000000, PP);
+ __ CompareImmediate(result, 0xC000000000000000);
__ b(&do_call, MI);
__ SmiTag(result);
if (FLAG_throw_on_javascript_int_overflow) {
@@ -4695,7 +4680,7 @@
__ fcvtzds(result, value);
// Check for overflow and that it fits into Smi.
- __ CompareImmediate(result, 0xC000000000000000, PP);
+ __ CompareImmediate(result, 0xC000000000000000);
__ b(deopt, MI);
__ SmiTag(result);
if (FLAG_throw_on_javascript_int_overflow) {
@@ -4803,7 +4788,7 @@
Label skip_call, try_sqrt, check_base, return_nan, do_pow;
__ fmovdd(saved_base, base);
- __ LoadDImmediate(result, 1.0, PP);
+ __ LoadDImmediate(result, 1.0);
// exponent == 0.0 -> return 1.0;
__ fcmpdz(exp);
__ b(&check_base, VS); // NaN -> check base.
@@ -4815,13 +4800,13 @@
__ b(&return_base, EQ);
// exponent == 2.0 ?
- __ LoadDImmediate(VTMP, 2.0, PP);
+ __ LoadDImmediate(VTMP, 2.0);
__ fcmpd(exp, VTMP);
Label return_base_times_2;
__ b(&return_base_times_2, EQ);
// exponent == 3.0 ?
- __ LoadDImmediate(VTMP, 3.0, PP);
+ __ LoadDImmediate(VTMP, 3.0);
__ fcmpd(exp, VTMP);
__ b(&check_base, NE);
@@ -4849,21 +4834,21 @@
__ b(&try_sqrt, VC); // // Neither 'exp' nor 'base' is NaN.
__ Bind(&return_nan);
- __ LoadDImmediate(result, NAN, PP);
+ __ LoadDImmediate(result, NAN);
__ b(&skip_call);
Label return_zero;
__ Bind(&try_sqrt);
// Before calling pow, check if we could use sqrt instead of pow.
- __ LoadDImmediate(result, kNegInfinity, PP);
+ __ LoadDImmediate(result, kNegInfinity);
// base == -Infinity -> call pow;
__ fcmpd(saved_base, result);
__ b(&do_pow, EQ);
// exponent == 0.5 ?
- __ LoadDImmediate(result, 0.5, PP);
+ __ LoadDImmediate(result, 0.5);
__ fcmpd(exp, result);
__ b(&do_pow, NE);
@@ -4875,7 +4860,7 @@
__ b(&skip_call);
__ Bind(&return_zero);
- __ LoadDImmediate(result, 0.0, PP);
+ __ LoadDImmediate(result, 0.0);
__ b(&skip_call);
__ Bind(&do_pow);
@@ -4990,7 +4975,7 @@
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(result_div, 0x4000000000000000, PP);
+ __ CompareImmediate(result_div, 0x4000000000000000);
__ b(deopt, EQ);
// result_mod <- left - right * result_div.
__ msub(result_mod, TMP, result_div, result_mod);
@@ -5069,7 +5054,7 @@
ICData::kDeoptCheckClass,
licm_hoisted_ ? ICData::kHoisted : 0);
if (IsNullCheck()) {
- __ CompareObject(locs()->in(0).reg(), Object::null_object(), PP);
+ __ CompareObject(locs()->in(0).reg(), Object::null_object());
ASSERT(DeoptIfNull() || DeoptIfNotNull());
Condition cond = DeoptIfNull() ? EQ : NE;
__ b(deopt, cond);
@@ -5088,12 +5073,12 @@
__ tsti(value, Immediate(kSmiTagMask));
__ b(deopt, EQ);
}
- __ LoadClassId(temp, value, PP);
+ __ LoadClassId(temp, value);
if (IsDenseSwitch()) {
ASSERT(cids_[0] < cids_[cids_.length() - 1]);
- __ AddImmediate(temp, temp, -cids_[0], PP);
- __ CompareImmediate(temp, cids_[cids_.length() - 1] - cids_[0], PP);
+ __ AddImmediate(temp, temp, -cids_[0]);
+ __ CompareImmediate(temp, cids_[cids_.length() - 1] - cids_[0]);
__ b(deopt, HI);
intptr_t mask = ComputeCidMask();
@@ -5101,9 +5086,9 @@
// Only need mask if there are missing numbers in the range.
ASSERT(cids_.length() > 2);
Register mask_reg = locs()->temp(1).reg();
- __ LoadImmediate(mask_reg, 1, PP);
+ __ LoadImmediate(mask_reg, 1);
__ lslv(mask_reg, mask_reg, temp);
- __ TestImmediate(mask_reg, mask, PP);
+ __ TestImmediate(mask_reg, mask);
__ b(deopt, EQ);
}
@@ -5116,7 +5101,7 @@
for (intptr_t i = 0; i < num_checks; i++) {
const intptr_t cid = sorted_ic_data[i].cid;
ASSERT(cid != kSmiCid);
- __ CompareImmediate(temp, cid, PP);
+ __ CompareImmediate(temp, cid);
if (i == (num_checks - 1)) {
__ b(deopt, NE);
} else {
@@ -5142,7 +5127,7 @@
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
- __ CompareImmediate(value, Smi::RawValue(cid_), PP);
+ __ CompareImmediate(value, Smi::RawValue(cid_));
__ b(deopt, NE);
}
@@ -5211,7 +5196,7 @@
if (index_loc.IsConstant()) {
const Register length = length_loc.reg();
const Smi& index = Smi::Cast(index_loc.constant());
- __ CompareImmediate(length, reinterpret_cast<int64_t>(index.raw()), PP);
+ __ CompareImmediate(length, reinterpret_cast<int64_t>(index.raw()));
__ b(deopt, LS);
} else if (length_loc.IsConstant()) {
const Smi& length = Smi::Cast(length_loc.constant());
@@ -5220,7 +5205,7 @@
__ tst(index, Operand(index));
__ b(deopt, MI);
} else {
- __ CompareImmediate(index, reinterpret_cast<int64_t>(length.raw()), PP);
+ __ CompareImmediate(index, reinterpret_cast<int64_t>(length.raw()));
__ b(deopt, CS);
}
} else {
@@ -5536,10 +5521,10 @@
const Register result = locs()->out(0).reg();
Label done;
__ Bind(&is_false);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ b(&done);
__ Bind(&is_true);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -5567,8 +5552,8 @@
const Register value = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ LoadObject(result, Bool::True(), PP);
- __ LoadObject(TMP, Bool::False(), PP);
+ __ LoadObject(result, Bool::True());
+ __ LoadObject(TMP, Bool::False());
__ CompareRegisters(result, value);
__ csel(result, TMP, result, EQ);
}
@@ -5582,12 +5567,11 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
const Code& stub = Code::Handle(isolate,
- stub_code->GetAllocationStubForClass(cls()));
- const ExternalLabel label(stub.EntryPoint());
+ StubCode::GetAllocationStubForClass(cls()));
+ const StubEntry stub_entry(stub);
compiler->GenerateCall(token_pos(),
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs());
compiler->AddStubCallTarget(stub);
@@ -5597,9 +5581,8 @@
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
- compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
+ compiler->GenerateCall(
+ token_pos(), *StubCode::DebugStepCheck_entry(), stub_kind_, locs());
}
@@ -5618,7 +5601,7 @@
void GrowRegExpStackInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register typed_data = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ Push(typed_data);
compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
deopt_id(),
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 2865b26..2e02c21 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -818,7 +818,6 @@
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
const bool is_leaf_call =
(argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
- StubCode* stub_code = compiler->isolate()->stub_code();
// Push the result place holder initialized to NULL.
__ PushObject(Object::null_object());
@@ -831,11 +830,11 @@
}
__ movl(ECX, Immediate(reinterpret_cast<uword>(native_c_function())));
__ movl(EDX, Immediate(argc_tag));
- const ExternalLabel* stub_entry = (is_bootstrap_native() || is_leaf_call) ?
- &stub_code->CallBootstrapCFunctionLabel() :
- &stub_code->CallNativeCFunctionLabel();
+ const StubEntry* stub_entry = (is_bootstrap_native() || is_leaf_call) ?
+ StubCode::CallBootstrapCFunction_entry() :
+ StubCode::CallNativeCFunction_entry();
compiler->GenerateCall(token_pos(),
- stub_entry,
+ *stub_entry,
RawPcDescriptors::kOther,
locs());
__ popl(result);
@@ -1650,7 +1649,6 @@
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
@@ -1659,8 +1657,8 @@
}
__ Bind(entry_label());
const Code& stub =
- Code::Handle(isolate, stub_code->GetAllocationStubForClass(cls_));
- const ExternalLabel label(stub.EntryPoint());
+ Code::Handle(isolate, StubCode::GetAllocationStubForClass(cls_));
+ const StubEntry stub_entry(stub);
LocationSummary* locs = instruction_->locs();
@@ -1668,9 +1666,10 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs);
+ compiler->AddStubCallTarget(stub);
__ MoveRegister(result_, EAX);
compiler->RestoreLiveRegisters(locs);
__ jmp(exit_label());
@@ -2053,7 +2052,8 @@
// Object end address in EBX.
__ TryAllocateArray(kArrayCid, instance_size, slow_path, Assembler::kFarJump,
EAX, // instance
- EBX); // end address
+ EBX, // end address
+ EDI); // temp
// Store the type argument field.
__ InitializeFieldNoBarrier(EAX,
@@ -2128,15 +2128,10 @@
}
__ Bind(&slow_path);
- Isolate* isolate = compiler->isolate();
- const Code& stub = Code::Handle(
- isolate, isolate->stub_code()->GetAllocateArrayStub());
- const ExternalLabel label(stub.EntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
locs());
- compiler->AddStubCallTarget(stub);
__ Bind(&done);
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2379,10 +2374,11 @@
bool opt) const {
ASSERT(opt);
const intptr_t kNumInputs = 0;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 2;
LocationSummary* locs = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
locs->set_temp(0, Location::RegisterLocation(ECX));
+ locs->set_temp(1, Location::RegisterLocation(EDI));
locs->set_out(0, Location::RegisterLocation(EAX));
return locs;
}
@@ -2404,10 +2400,8 @@
compiler->SaveLiveRegisters(locs);
__ movl(EDX, Immediate(instruction_->num_context_variables()));
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
compiler->GenerateCall(instruction_->token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs);
ASSERT(instruction_->locs()->out(0).reg() == EAX);
@@ -2424,6 +2418,7 @@
FlowGraphCompiler* compiler) {
ASSERT(compiler->is_optimizing());
Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
Register result = locs()->out(0).reg();
// Try allocate the object.
AllocateContextSlowPath* slow_path = new AllocateContextSlowPath(this);
@@ -2433,7 +2428,8 @@
__ TryAllocateArray(kContextCid, instance_size, slow_path->entry_label(),
Assembler::kFarJump,
result, // instance
- temp); // end address
+ temp, // end address
+ temp2); // temp
// Setup up number of context variables field.
__ movl(FieldAddress(result, Context::num_variables_offset()),
@@ -2460,10 +2456,8 @@
ASSERT(locs()->out(0).reg() == EAX);
__ movl(EDX, Immediate(num_context_variables()));
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs());
}
@@ -2572,11 +2566,14 @@
LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 0;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = opt ? 0 : 1;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs,
kNumTemps,
LocationSummary::kCallOnSlowPath);
+ if (!opt) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
return summary;
}
@@ -2634,8 +2631,13 @@
CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
compiler->AddSlowPathCode(slow_path);
- __ cmpl(ESP,
- Address::Absolute(Isolate::Current()->stack_limit_address()));
+ if (compiler->is_optimizing()) {
+ __ cmpl(ESP, Address::Absolute(Isolate::Current()->stack_limit_address()));
+ } else {
+ Register tmp = locs()->temp(0).reg();
+ __ LoadIsolate(tmp);
+ __ cmpl(ESP, Address(tmp, Isolate::stack_limit_offset()));
+ }
__ j(BELOW_EQUAL, slow_path->entry_label());
if (compiler->CanOSRFunction() && in_loop()) {
// In unoptimized code check the usage counter to trigger OSR at loop
@@ -3324,10 +3326,11 @@
LocationSummary* BoxInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = 1;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_temp(0, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
@@ -3342,7 +3345,7 @@
this,
compiler->BoxClassFor(from_representation()),
out_reg,
- kNoRegister);
+ locs()->temp(0).reg());
switch (from_representation()) {
case kUnboxedDouble:
@@ -3490,7 +3493,7 @@
LocationSummary* BoxInteger32Instr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps,
ValueFitsSmi() ? LocationSummary::kNoCall
@@ -3499,6 +3502,9 @@
(from_representation() == kUnboxedUint32);
summary->set_in(0, needs_writable_input ? Location::RequiresRegister()
: Location::WritableRegister());
+ if (!ValueFitsSmi()) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
summary->set_out(0, ValueFitsSmi() ? Location::SameAsFirstInput()
: Location::RequiresRegister());
return summary;
@@ -3526,7 +3532,7 @@
// on the slow path.
locs()->live_registers()->Add(locs()->in(0), kUnboxedInt32);
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->mint_class(), out, kNoRegister);
+ compiler, this, compiler->mint_class(), out, locs()->temp(0).reg());
__ movl(FieldAddress(out, Mint::value_offset()), value);
if (from_representation() == kUnboxedInt32) {
__ sarl(value, Immediate(31)); // Sign extend.
@@ -3601,7 +3607,7 @@
__ subl(value_lo, Immediate(0x40000000));
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->mint_class(), out_reg, kNoRegister);
+ compiler, this, compiler->mint_class(), out_reg, locs()->temp(0).reg());
__ movl(FieldAddress(out_reg, Mint::value_offset()), value_lo);
__ movl(FieldAddress(out_reg, Mint::value_offset() + kWordSize), value_hi);
__ Bind(&done);
@@ -3708,7 +3714,7 @@
bool opt) const {
const bool might_box = (representation() == kTagged) && !can_pack_into_smi();
const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = might_box ? 1 : 0;
+ const intptr_t kNumTemps = might_box ? 2 : 0;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps,
might_box ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
@@ -3719,6 +3725,7 @@
: Location::RequiresRegister());
if (might_box) {
summary->set_temp(0, Location::RequiresRegister());
+ summary->set_temp(1, Location::RequiresRegister());
}
if (representation() == kUnboxedMint) {
@@ -3798,6 +3805,7 @@
} else {
// If the value cannot fit in a smi then allocate a mint box for it.
Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
// Temp register needs to be manually preserved on allocation slow-path.
locs()->live_registers()->Add(locs()->temp(0), kUnboxedInt32);
@@ -3809,7 +3817,7 @@
__ testl(temp, Immediate(0xC0000000));
__ j(ZERO, &done);
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->mint_class(), result, kNoRegister);
+ compiler, this, compiler->mint_class(), result, temp2);
__ movl(FieldAddress(result, Mint::value_offset()), temp);
__ movl(FieldAddress(result, Mint::value_offset() + kWordSize),
Immediate(0));
@@ -6802,12 +6810,11 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
const Code& stub = Code::Handle(isolate,
- stub_code->GetAllocationStubForClass(cls()));
- const ExternalLabel label(stub.EntryPoint());
+ StubCode::GetAllocationStubForClass(cls()));
+ const StubEntry stub_entry(stub);
compiler->GenerateCall(token_pos(),
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs());
compiler->AddStubCallTarget(stub);
@@ -6817,9 +6824,10 @@
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
- compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
+ compiler->GenerateCall(token_pos(),
+ *StubCode::DebugStepCheck_entry(),
+ stub_kind_,
+ locs());
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 07a8242..df32f00 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -993,10 +993,9 @@
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
const bool is_leaf_call =
(argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel* stub_entry;
+ const StubEntry* stub_entry = NULL;
if (is_bootstrap_native() || is_leaf_call) {
- stub_entry = &stub_code->CallBootstrapCFunctionLabel();
+ stub_entry = StubCode::CallBootstrapCFunction_entry();
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kBootstrapNativeCall, function().NumParameters());
@@ -1005,7 +1004,7 @@
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = &stub_code->CallNativeCFunctionLabel();
+ stub_entry = StubCode::CallNativeCFunction_entry();
#if defined(USING_SIMULATOR)
if (!function().IsNativeAutoSetupScope()) {
entry = Simulator::RedirectExternalReference(
@@ -1016,7 +1015,7 @@
__ LoadImmediate(T5, entry);
__ LoadImmediate(A1, argc_tag);
compiler->GenerateCall(token_pos(),
- stub_entry,
+ *stub_entry,
RawPcDescriptors::kOther,
locs());
__ Pop(result);
@@ -1035,6 +1034,7 @@
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(compiler->is_optimizing());
Register char_code = locs()->in(0).reg();
Register result = locs()->out(0).reg();
@@ -1838,7 +1838,6 @@
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
@@ -1847,17 +1846,18 @@
}
__ Bind(entry_label());
const Code& stub =
- Code::Handle(isolate, stub_code->GetAllocationStubForClass(cls_));
- const ExternalLabel label(stub.EntryPoint());
+ Code::Handle(isolate, StubCode::GetAllocationStubForClass(cls_));
+ const StubEntry stub_entry(stub);
LocationSummary* locs = instruction_->locs();
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs);
+ compiler->AddStubCallTarget(stub);
if (result_ != V0) {
__ mov(result_, V0);
}
@@ -2246,15 +2246,10 @@
}
__ Bind(&slow_path);
- Isolate* isolate = compiler->isolate();
- const Code& stub = Code::Handle(
- isolate, isolate->stub_code()->GetAllocateArrayStub());
- const ExternalLabel label(stub.EntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
locs());
- compiler->AddStubCallTarget(stub);
__ Bind(&done);
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2500,10 +2495,8 @@
compiler->SaveLiveRegisters(locs);
__ LoadImmediate(T1, instruction_->num_context_variables());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
compiler->GenerateCall(instruction_->token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs);
ASSERT(instruction_->locs()->out(0).reg() == V0);
@@ -2559,10 +2552,8 @@
__ Comment("AllocateContextInstr");
__ LoadImmediate(T1, num_context_variables());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs());
}
@@ -2752,8 +2743,13 @@
CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
compiler->AddSlowPathCode(slow_path);
- __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address());
- __ lw(CMPRES1, Address(TMP));
+ if (compiler->is_optimizing()) {
+ __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address());
+ __ lw(CMPRES1, Address(TMP));
+ } else {
+ __ LoadIsolate(TMP);
+ __ lw(CMPRES1, Address(TMP, Isolate::stack_limit_offset()));
+ }
__ BranchUnsignedLessEqual(SP, CMPRES1, slow_path->entry_label());
if (compiler->CanOSRFunction() && in_loop()) {
Register temp = locs()->temp(0).reg();
@@ -5544,12 +5540,11 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ Comment("AllocateObjectInstr");
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
const Code& stub = Code::Handle(isolate,
- stub_code->GetAllocationStubForClass(cls()));
- const ExternalLabel label(stub.EntryPoint());
+ StubCode::GetAllocationStubForClass(cls()));
+ const StubEntry stub_entry(stub);
compiler->GenerateCall(token_pos(),
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs());
compiler->AddStubCallTarget(stub);
@@ -5559,9 +5554,8 @@
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
- compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
+ compiler->GenerateCall(
+ token_pos(), *StubCode::DebugStepCheck_entry(), stub_kind_, locs());
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index ec0bbc7..84afa6f 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -56,7 +56,7 @@
if (value.IsRegister()) {
__ pushq(value.reg());
} else if (value.IsConstant()) {
- __ PushObject(value.constant(), PP);
+ __ PushObject(value.constant());
} else {
ASSERT(value.IsStackSlot());
__ pushq(value.ToStackSlotAddress());
@@ -97,13 +97,17 @@
ASSERT(fp_sp_dist <= 0);
__ movq(RDI, RSP);
__ subq(RDI, RBP);
- __ CompareImmediate(RDI, Immediate(fp_sp_dist), PP);
+ __ CompareImmediate(RDI, Immediate(fp_sp_dist));
__ j(EQUAL, &done, Assembler::kNearJump);
__ int3();
__ Bind(&done);
#endif
- __ LeaveDartFrame();
+ ASSERT(__ constant_pool_allowed());
+ __ LeaveDartFrame(); // Disallows constant pool use.
__ ret();
+ // This ReturnInstr may be emitted out of order by the optimizer. The next
+ // block may be a target expecting a properly set constant pool pointer.
+ __ set_constant_pool_allowed(true);
}
@@ -183,9 +187,9 @@
} else {
__ decq(RDX);
__ AndImmediate(RDX,
- Immediate(Smi::RawValue(true_value) - Smi::RawValue(false_value)), PP);
+ Immediate(Smi::RawValue(true_value) - Smi::RawValue(false_value)));
if (false_value != 0) {
- __ AddImmediate(RDX, Immediate(Smi::RawValue(false_value)), PP);
+ __ AddImmediate(RDX, Immediate(Smi::RawValue(false_value)));
}
}
}
@@ -242,7 +246,7 @@
// The register allocator drops constant definitions that have no uses.
if (!locs()->out(0).IsInvalid()) {
Register result = locs()->out(0).reg();
- __ LoadObject(result, value(), PP);
+ __ LoadObject(result, value());
}
}
@@ -277,7 +281,7 @@
if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) {
__ xorps(result, result);
} else {
- __ LoadObject(TMP, value(), PP);
+ __ LoadObject(TMP, value());
__ movsd(result, FieldAddress(TMP, Double::value_offset()));
}
break;
@@ -330,13 +334,13 @@
Label done;
if (Isolate::Current()->flags().type_checks()) {
- __ CompareObject(reg, Bool::True(), PP);
+ __ CompareObject(reg, Bool::True());
__ j(EQUAL, &done, Assembler::kNearJump);
- __ CompareObject(reg, Bool::False(), PP);
+ __ CompareObject(reg, Bool::False());
__ j(EQUAL, &done, Assembler::kNearJump);
} else {
ASSERT(Isolate::Current()->flags().asserts());
- __ CompareObject(reg, Object::null_instance(), PP);
+ __ CompareObject(reg, Object::null_instance());
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
}
@@ -422,7 +426,7 @@
Label* value_is_smi = NULL) {
Label done;
if (value_is_smi == NULL) {
- __ LoadImmediate(value_cid_reg, Immediate(kSmiCid), PP);
+ __ LoadImmediate(value_cid_reg, Immediate(kSmiCid));
}
__ testq(value_reg, Immediate(kSmiTagMask));
if (value_is_smi == NULL) {
@@ -484,10 +488,10 @@
Condition true_condition = TokenKindToIntCondition(kind);
if (left.IsConstant()) {
- __ CompareObject(right.reg(), left.constant(), PP);
+ __ CompareObject(right.reg(), left.constant());
true_condition = FlipCondition(true_condition);
} else if (right.IsConstant()) {
- __ CompareObject(left.reg(), right.constant(), PP);
+ __ CompareObject(left.reg(), right.constant());
} else if (right.IsStackSlot()) {
__ cmpq(left.reg(), right.ToStackSlotAddress());
} else {
@@ -551,10 +555,10 @@
Register result = locs()->out(0).reg();
Label done;
__ Bind(&is_false);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ jmp(&done);
__ Bind(&is_true);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -591,7 +595,7 @@
ASSERT(right.constant().IsSmi());
const int64_t imm =
reinterpret_cast<int64_t>(right.constant().raw());
- __ TestImmediate(left_reg, Immediate(imm), PP);
+ __ TestImmediate(left_reg, Immediate(imm));
} else {
__ testq(left_reg, right.reg());
}
@@ -679,10 +683,10 @@
BranchLabels labels = { &is_true, &is_false, &is_false };
EmitComparisonCode(compiler, labels);
__ Bind(&is_false);
- __ LoadObject(result_reg, Bool::False(), PP);
+ __ LoadObject(result_reg, Bool::False());
__ jmp(&done, Assembler::kNearJump);
__ Bind(&is_true);
- __ LoadObject(result_reg, Bool::True(), PP);
+ __ LoadObject(result_reg, Bool::True());
__ Bind(&done);
}
@@ -740,10 +744,10 @@
Register result = locs()->out(0).reg();
Label done;
__ Bind(&is_false);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ jmp(&done);
__ Bind(&is_true);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -767,25 +771,22 @@
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
const bool is_leaf_call =
(argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
- StubCode* stub_code = compiler->isolate()->stub_code();
// Push the result place holder initialized to NULL.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
// Pass a pointer to the first argument in RAX.
if (!function().HasOptionalParameters()) {
__ leaq(RAX, Address(RBP, (kParamEndSlotFromFp +
function().NumParameters()) * kWordSize));
} else {
- __ leaq(RAX,
- Address(RBP, kFirstLocalSlotFromFp * kWordSize));
+ __ leaq(RAX, Address(RBP, kFirstLocalSlotFromFp * kWordSize));
}
__ LoadImmediate(
- RBX, Immediate(reinterpret_cast<uword>(native_c_function())), PP);
- __ LoadImmediate(
- R10, Immediate(argc_tag), PP);
- const ExternalLabel* stub_entry = (is_bootstrap_native() || is_leaf_call) ?
- &stub_code->CallBootstrapCFunctionLabel() :
- &stub_code->CallNativeCFunctionLabel();
+ RBX, Immediate(reinterpret_cast<uword>(native_c_function())));
+ __ LoadImmediate(R10, Immediate(argc_tag));
+ const StubEntry& stub_entry = (is_bootstrap_native() || is_leaf_call) ?
+ *StubCode::CallBootstrapCFunction_entry() :
+ *StubCode::CallNativeCFunction_entry();
compiler->GenerateCall(token_pos(),
stub_entry,
RawPcDescriptors::kOther,
@@ -818,10 +819,11 @@
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(compiler->is_optimizing());
Register char_code = locs()->in(0).reg();
Register result = locs()->out(0).reg();
__ LoadImmediate(result,
- Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())), PP);
+ Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())));
__ movq(result, Address(result,
char_code,
TIMES_HALF_WORD_SIZE, // Char code is a smi.
@@ -926,7 +928,7 @@
// 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)), PP);
+ __ LoadImmediate(result, Immediate(Smi::RawValue(kSmiCid)));
__ jmp(&done);
__ Bind(&load);
__ LoadClassId(result, object);
@@ -1319,7 +1321,7 @@
__ StoreIntoObject(array, element_address, value);
} else if (locs()->in(2).IsConstant()) {
const Object& constant = locs()->in(2).constant();
- __ StoreIntoObjectNoBarrier(array, element_address, constant, PP);
+ __ StoreIntoObjectNoBarrier(array, element_address, constant);
} else {
Register value = locs()->in(2).reg();
__ StoreIntoObjectNoBarrier(array, element_address, value);
@@ -1356,14 +1358,14 @@
ASSERT(locs()->in(2).reg() == RAX);
Label store_value, store_0xff;
__ SmiUntag(RAX);
- __ CompareImmediate(RAX, Immediate(0xFF), PP);
+ __ CompareImmediate(RAX, Immediate(0xFF));
__ j(BELOW_EQUAL, &store_value, Assembler::kNearJump);
// Clamp to 0x0 or 0xFF respectively.
__ j(GREATER, &store_0xff);
__ xorq(RAX, RAX);
__ jmp(&store_value, Assembler::kNearJump);
__ Bind(&store_0xff);
- __ LoadImmediate(RAX, Immediate(0xFF), PP);
+ __ LoadImmediate(RAX, Immediate(0xFF));
__ Bind(&store_value);
__ movb(element_address, RAX);
}
@@ -1472,7 +1474,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
@@ -1541,12 +1543,12 @@
if (field_cid != kSmiCid) {
__ j(ZERO, fail);
__ LoadClassId(value_cid_reg, value_reg);
- __ CompareImmediate(value_cid_reg, Immediate(field_cid), PP);
+ __ CompareImmediate(value_cid_reg, Immediate(field_cid));
}
if (field().is_nullable() && (field_cid != kNullCid)) {
__ j(EQUAL, &ok);
- __ CompareObject(value_reg, Object::null_object(), PP);
+ __ CompareObject(value_reg, Object::null_object());
}
__ j(NOT_EQUAL, fail);
@@ -1602,7 +1604,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
__ movsxb(offset_reg, FieldAddress(field_reg,
Field::guarded_list_length_in_object_offset_offset()));
@@ -1639,8 +1641,7 @@
__ CompareImmediate(
FieldAddress(value_reg,
field().guarded_list_length_in_object_offset()),
- Immediate(Smi::RawValue(field().guarded_list_length())),
- PP);
+ Immediate(Smi::RawValue(field().guarded_list_length())));
__ j(NOT_EQUAL, deopt);
}
}
@@ -1657,7 +1658,6 @@
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
@@ -1666,8 +1666,8 @@
}
__ Bind(entry_label());
const Code& stub =
- Code::Handle(isolate, stub_code->GetAllocationStubForClass(cls_));
- const ExternalLabel label(stub.EntryPoint());
+ Code::Handle(isolate, StubCode::GetAllocationStubForClass(cls_));
+ const StubEntry stub_entry(stub);
LocationSummary* locs = instruction_->locs();
@@ -1675,9 +1675,10 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs);
+ compiler->AddStubCallTarget(stub);
__ MoveRegister(result_, RAX);
compiler->RestoreLiveRegisters(locs);
__ jmp(exit_label());
@@ -1686,13 +1687,14 @@
static void Allocate(FlowGraphCompiler* compiler,
Instruction* instruction,
const Class& cls,
- Register result) {
+ Register result,
+ Register temp) {
if (compiler->intrinsic_mode()) {
__ TryAllocate(cls,
compiler->intrinsic_slow_path_label(),
Assembler::kFarJump,
result,
- PP);
+ temp);
} else {
BoxAllocationSlowPath* slow_path =
new BoxAllocationSlowPath(instruction, cls, result);
@@ -1702,7 +1704,7 @@
slow_path->entry_label(),
Assembler::kFarJump,
result,
- PP);
+ temp);
__ Bind(slow_path->exit_label());
}
}
@@ -1758,9 +1760,9 @@
Register temp) {
Label done;
__ movq(box_reg, FieldAddress(instance_reg, offset));
- __ CompareObject(box_reg, Object::null_object(), PP);
+ __ CompareObject(box_reg, Object::null_object());
__ j(NOT_EQUAL, &done);
- BoxAllocationSlowPath::Allocate(compiler, instruction, cls, box_reg);
+ BoxAllocationSlowPath::Allocate(compiler, instruction, cls, box_reg, temp);
__ movq(temp, box_reg);
__ StoreIntoObject(instance_reg,
FieldAddress(instance_reg, offset),
@@ -1798,7 +1800,7 @@
UNREACHABLE();
}
- BoxAllocationSlowPath::Allocate(compiler, this, *cls, temp);
+ BoxAllocationSlowPath::Allocate(compiler, this, *cls, temp, temp2);
__ movq(temp2, temp);
__ StoreIntoObject(instance_reg,
FieldAddress(instance_reg, offset_in_bytes_),
@@ -1842,7 +1844,7 @@
Label store_float32x4;
Label store_float64x2;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP);
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()));
__ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
Immediate(kNullCid));
@@ -1928,7 +1930,6 @@
__ StoreIntoObjectNoBarrier(instance_reg,
FieldAddress(instance_reg, offset_in_bytes_),
locs()->in(1).constant(),
- PP,
is_object_reference_initialization_ ?
Assembler::kEmptyOrSmiOrNull :
Assembler::kHeapObjectOrSmi);
@@ -1985,7 +1986,7 @@
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field(), PP);
+ __ LoadObject(temp, field());
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObject(temp,
FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
@@ -2051,7 +2052,8 @@
__ TryAllocateArray(kArrayCid, instance_size, slow_path, Assembler::kFarJump,
RAX, // instance
- RCX); // end address
+ RCX, // end address
+ R13); // temp
// RAX: new object start as a tagged pointer.
// Store the type argument field.
@@ -2071,7 +2073,7 @@
// data area to be initialized.
if (num_elements > 0) {
const intptr_t array_size = instance_size - sizeof(RawArray);
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
__ leaq(RDI, FieldAddress(RAX, sizeof(RawArray)));
if (array_size < (kInlineArraySize * kWordSize)) {
intptr_t current_offset = 0;
@@ -2109,7 +2111,7 @@
Label slow_path, done;
InlineArrayAllocation(compiler, length, &slow_path, &done);
__ Bind(&slow_path);
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ pushq(kLengthReg);
__ pushq(kElemTypeReg);
compiler->GenerateRuntimeCall(token_pos(),
@@ -2125,15 +2127,10 @@
}
__ Bind(&slow_path);
- Isolate* isolate = compiler->isolate();
- const Code& stub = Code::Handle(
- isolate, isolate->stub_code()->GetAllocateArrayStub());
- const ExternalLabel label(stub.EntryPoint());
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
locs());
- compiler->AddStubCallTarget(stub);
__ Bind(&done);
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2203,7 +2200,7 @@
Label load_float32x4;
Label load_float64x2;
- __ LoadObject(result, Field::ZoneHandle(field()->raw()), PP);
+ __ LoadObject(result, Field::ZoneHandle(field()->raw()));
__ cmpl(FieldAddress(result, Field::is_nullable_offset()),
Immediate(kNullCid));
@@ -2231,7 +2228,7 @@
{
__ Bind(&load_double);
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->double_class(), result);
+ compiler, this, compiler->double_class(), result, temp);
__ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
__ movsd(value, FieldAddress(temp, Double::value_offset()));
__ movsd(FieldAddress(result, Double::value_offset()), value);
@@ -2241,7 +2238,7 @@
{
__ Bind(&load_float32x4);
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->float32x4_class(), result);
+ compiler, this, compiler->float32x4_class(), result, temp);
__ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
__ movups(value, FieldAddress(temp, Float32x4::value_offset()));
__ movups(FieldAddress(result, Float32x4::value_offset()), value);
@@ -2251,7 +2248,7 @@
{
__ Bind(&load_float64x2);
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->float64x2_class(), result);
+ compiler, this, compiler->float64x2_class(), result, temp);
__ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
__ movups(value, FieldAddress(temp, Float64x2::value_offset()));
__ movups(FieldAddress(result, Float64x2::value_offset()), value);
@@ -2283,8 +2280,8 @@
// 'instantiator_reg' is the instantiator TypeArguments object (or null).
// A runtime call to instantiate the type is required.
- __ PushObject(Object::null_object(), PP); // Make room for the result.
- __ PushObject(type(), PP);
+ __ PushObject(Object::null_object()); // Make room for the result.
+ __ PushObject(type());
__ pushq(instantiator_reg); // Push instantiator type arguments.
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2326,14 +2323,14 @@
Label type_arguments_instantiated;
const intptr_t len = type_arguments().Length();
if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ CompareObject(instantiator_reg, Object::null_object(), PP);
+ __ CompareObject(instantiator_reg, Object::null_object());
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
}
// Lookup cache before calling runtime.
// TODO(fschneider): Consider moving this into a shared stub to reduce
// generated code size.
- __ LoadObject(RDI, type_arguments(), PP);
+ __ LoadObject(RDI, type_arguments());
__ movq(RDI, FieldAddress(RDI, TypeArguments::instantiations_offset()));
__ leaq(RDI, FieldAddress(RDI, Array::data_offset()));
// The instantiations cache is initialized with Object::zero_array() and is
@@ -2354,8 +2351,8 @@
__ Bind(&slow_case);
// Instantiate non-null type arguments.
// A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::null_object(), PP); // Make room for the result.
- __ PushObject(type_arguments(), PP);
+ __ PushObject(Object::null_object()); // Make room for the result.
+ __ PushObject(type_arguments());
__ pushq(instantiator_reg); // Push instantiator type arguments.
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2374,10 +2371,11 @@
bool opt) const {
ASSERT(opt);
const intptr_t kNumInputs = 0;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 2;
LocationSummary* locs = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
locs->set_temp(0, Location::RegisterLocation(R10));
+ locs->set_temp(1, Location::RegisterLocation(R13));
locs->set_out(0, Location::RegisterLocation(RAX));
return locs;
}
@@ -2398,11 +2396,9 @@
compiler->SaveLiveRegisters(locs);
- __ LoadImmediate(R10, Immediate(instruction_->num_context_variables()), PP);
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
+ __ LoadImmediate(R10, Immediate(instruction_->num_context_variables()));
compiler->GenerateCall(instruction_->token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs);
ASSERT(instruction_->locs()->out(0).reg() == RAX);
@@ -2428,7 +2424,8 @@
__ TryAllocateArray(kContextCid, instance_size, slow_path->entry_label(),
Assembler::kFarJump,
result, // instance
- temp); // end address
+ temp, // end address
+ locs()->temp(1).reg());
// Setup up number of context variables field.
__ movq(FieldAddress(result, Context::num_variables_offset()),
@@ -2453,12 +2450,10 @@
void AllocateContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(locs()->temp(0).reg() == R10);
ASSERT(locs()->out(0).reg() == RAX);
- StubCode* stub_code = compiler->isolate()->stub_code();
- __ LoadImmediate(R10, Immediate(num_context_variables()), PP);
- const ExternalLabel label(stub_code->AllocateContextEntryPoint());
+ __ LoadImmediate(R10, Immediate(num_context_variables()));
compiler->GenerateCall(token_pos(),
- &label,
+ *StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
locs());
}
@@ -2483,14 +2478,14 @@
Label call_runtime, no_call;
__ movq(temp, FieldAddress(field, Field::value_offset()));
- __ CompareObject(temp, Object::sentinel(), PP);
+ __ CompareObject(temp, Object::sentinel());
__ j(EQUAL, &call_runtime);
- __ CompareObject(temp, Object::transition_sentinel(), PP);
+ __ CompareObject(temp, Object::transition_sentinel());
__ j(NOT_EQUAL, &no_call);
__ Bind(&call_runtime);
- __ PushObject(Object::null_object(), PP); // Make room for (unused) result.
+ __ PushObject(Object::null_object()); // Make room for (unused) result.
__ pushq(field);
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2518,7 +2513,7 @@
Register context_value = locs()->in(0).reg();
Register result = locs()->out(0).reg();
- __ PushObject(Object::null_object(), PP); // Make room for the result.
+ __ PushObject(Object::null_object()); // Make room for the result.
__ pushq(context_value);
compiler->GenerateRuntimeCall(token_pos(),
deopt_id(),
@@ -2546,7 +2541,7 @@
needs_stacktrace());
// Restore the pool pointer.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -2592,7 +2587,7 @@
Register temp = instruction_->locs()->temp(0).reg();
__ Comment("CheckStackOverflowSlowPathOsr");
__ Bind(osr_entry_label());
- __ LoadImmediate(temp, Immediate(flags_address), PP);
+ __ LoadImmediate(temp, Immediate(flags_address));
__ movq(Address(temp, 0), Immediate(Isolate::kOsrRequest));
}
__ Comment("CheckStackOverflowSlowPath");
@@ -2638,15 +2633,20 @@
Register temp = locs()->temp(0).reg();
// Generate stack overflow check.
- __ LoadImmediate(
- temp, Immediate(Isolate::Current()->stack_limit_address()), PP);
- __ cmpq(RSP, Address(temp, 0));
+ if (compiler->is_optimizing()) {
+ __ LoadImmediate(
+ temp, Immediate(Isolate::Current()->stack_limit_address()));
+ __ cmpq(RSP, Address(temp, 0));
+ } else {
+ __ LoadIsolate(temp);
+ __ cmpq(RSP, Address(temp, Isolate::stack_limit_offset()));
+ }
__ j(BELOW_EQUAL, slow_path->entry_label());
if (compiler->CanOSRFunction() && in_loop()) {
// In unoptimized code check the usage counter to trigger OSR at loop
// stack checks. Use progressively higher thresholds for more deeply
// nested loops to attempt to hit outer loops with OSR when possible.
- __ LoadObject(temp, compiler->parsed_function().function(), PP);
+ __ LoadObject(temp, compiler->parsed_function().function());
int32_t threshold =
FLAG_optimization_counter_threshold * (loop_depth() + 1);
__ cmpl(FieldAddress(temp, Function::usage_counter_offset()),
@@ -2668,9 +2668,9 @@
ASSERT(overflow != NULL);
// TODO(zra): This can be tightened to one compare/branch using:
// overflow = (result + 2^52) > 2^53 with an unsigned comparison.
- __ CompareImmediate(result, Immediate(-0x20000000000000LL), PP);
+ __ CompareImmediate(result, Immediate(-0x20000000000000LL));
__ j(LESS, overflow);
- __ CompareImmediate(result, Immediate(0x20000000000000LL), PP);
+ __ CompareImmediate(result, Immediate(0x20000000000000LL));
__ j(GREATER, overflow);
}
}
@@ -2719,7 +2719,7 @@
if (obj.IsSmi()) {
const intptr_t left_int = Smi::Cast(obj).Value();
if (left_int == 0) {
- __ CompareImmediate(right, Immediate(0), PP);
+ __ CompareImmediate(right, Immediate(0));
__ j(NEGATIVE, deopt);
return;
}
@@ -2728,7 +2728,7 @@
!RangeUtils::IsWithin(right_range, 0, max_right - 1);
if (right_needs_check) {
__ CompareImmediate(right,
- Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))), PP);
+ Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
__ j(ABOVE_EQUAL, deopt);
}
__ SmiUntag(right);
@@ -2749,12 +2749,12 @@
(right_range == NULL) || !right_range->IsPositive();
if (right_may_be_negative) {
ASSERT(shift_left->CanDeoptimize());
- __ CompareImmediate(right, Immediate(0), PP);
+ __ CompareImmediate(right, Immediate(0));
__ j(NEGATIVE, deopt);
}
Label done, is_not_zero;
__ CompareImmediate(right,
- Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))), PP);
+ Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
__ j(BELOW, &is_not_zero, Assembler::kNearJump);
__ xorq(left, left);
__ jmp(&done, Assembler::kNearJump);
@@ -2770,7 +2770,7 @@
if (right_needs_check) {
ASSERT(shift_left->CanDeoptimize());
__ CompareImmediate(right,
- Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))), PP);
+ Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
__ j(ABOVE_EQUAL, deopt);
}
// Left is not a constant.
@@ -2903,19 +2903,19 @@
const int64_t imm = reinterpret_cast<int64_t>(constant.raw());
switch (op_kind()) {
case Token::kADD: {
- __ AddImmediate(left, Immediate(imm), PP);
+ __ AddImmediate(left, Immediate(imm));
if (deopt != NULL) __ j(OVERFLOW, deopt);
break;
}
case Token::kSUB: {
- __ SubImmediate(left, Immediate(imm), PP);
+ __ SubImmediate(left, Immediate(imm));
if (deopt != NULL) __ j(OVERFLOW, deopt);
break;
}
case Token::kMUL: {
// Keep left value tagged and untag right value.
const intptr_t value = Smi::Cast(constant).Value();
- __ MulImmediate(left, Immediate(value), PP);
+ __ MulImmediate(left, Immediate(value));
if (deopt != NULL) __ j(OVERFLOW, deopt);
break;
}
@@ -2941,17 +2941,17 @@
}
case Token::kBIT_AND: {
// No overflow check.
- __ AndImmediate(left, Immediate(imm), PP);
+ __ AndImmediate(left, Immediate(imm));
break;
}
case Token::kBIT_OR: {
// No overflow check.
- __ OrImmediate(left, Immediate(imm), PP);
+ __ OrImmediate(left, Immediate(imm));
break;
}
case Token::kBIT_XOR: {
// No overflow check.
- __ XorImmediate(left, Immediate(imm), PP);
+ __ XorImmediate(left, Immediate(imm));
break;
}
@@ -3096,7 +3096,7 @@
__ idivq(right); // RAX: quotient, RDX: remainder.
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(result, Immediate(0x4000000000000000), PP);
+ __ CompareImmediate(result, Immediate(0x4000000000000000));
__ j(EQUAL, deopt);
__ Bind(&done);
__ SmiTag(result);
@@ -3176,7 +3176,7 @@
}
case Token::kSHR: {
if (CanDeoptimize()) {
- __ CompareImmediate(right, Immediate(0), PP);
+ __ CompareImmediate(right, Immediate(0));
__ j(LESS, deopt);
}
__ SmiUntag(right);
@@ -3184,10 +3184,10 @@
const intptr_t kCountLimit = 0x3F;
if ((right_range == NULL) ||
!right_range->OnlyLessThanOrEqualTo(kCountLimit)) {
- __ CompareImmediate(right, Immediate(kCountLimit), PP);
+ __ CompareImmediate(right, Immediate(kCountLimit));
Label count_ok;
__ j(LESS, &count_ok, Assembler::kNearJump);
- __ LoadImmediate(right, Immediate(kCountLimit), PP);
+ __ LoadImmediate(right, Immediate(kCountLimit));
__ Bind(&count_ok);
}
ASSERT(right == RCX); // Count must be in RCX
@@ -3265,10 +3265,11 @@
LocationSummary* BoxInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = 1;
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_temp(0, Location::RequiresRegister());
summary->set_out(0, Location::RequiresRegister());
return summary;
}
@@ -3276,10 +3277,12 @@
void BoxInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register out_reg = locs()->out(0).reg();
+ Register temp = locs()->temp(0).reg();
XmmRegister value = locs()->in(0).fpu_reg();
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->BoxClassFor(from_representation()), out_reg);
+ compiler, this, compiler->BoxClassFor(from_representation()), out_reg,
+ temp);
__ movsd(FieldAddress(out_reg, Double::value_offset()), value);
switch (from_representation()) {
case kUnboxedDouble:
@@ -3508,7 +3511,7 @@
LocationSummary* BoxInt64Instr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
LocationSummary* summary = new(zone) LocationSummary(
zone,
kNumInputs,
@@ -3516,6 +3519,9 @@
ValueFitsSmi() ? LocationSummary::kNoCall
: LocationSummary::kCallOnSlowPath);
summary->set_in(0, Location::RequiresRegister());
+ if (!ValueFitsSmi()) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
summary->set_out(0, Location::RequiresRegister());
return summary;
}
@@ -3527,10 +3533,11 @@
__ MoveRegister(out, value);
__ SmiTag(out);
if (!ValueFitsSmi()) {
+ const Register temp = locs()->temp(0).reg();
Label done;
__ j(NO_OVERFLOW, &done);
BoxAllocationSlowPath::Allocate(
- compiler, this, compiler->mint_class(), out);
+ compiler, this, compiler->mint_class(), out, temp);
__ movq(FieldAddress(out, Mint::value_offset()), value);
__ Bind(&done);
}
@@ -3737,7 +3744,7 @@
XmmRegister v2 = locs()->in(2).fpu_reg();
XmmRegister v3 = locs()->in(3).fpu_reg();
ASSERT(v0 == locs()->out(0).fpu_reg());
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
__ cvtsd2ss(v0, v0);
__ movss(Address(RSP, 0), v0);
__ movsd(v0, v1);
@@ -3750,7 +3757,7 @@
__ cvtsd2ss(v0, v0);
__ movss(Address(RSP, 12), v0);
__ movups(v0, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
}
@@ -4004,47 +4011,47 @@
switch (op_kind()) {
case MethodRecognizer::kFloat32x4WithX:
__ cvtsd2ss(replacement, replacement);
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
// Move value to stack.
__ movups(Address(RSP, 0), value);
// Write over X value.
__ movss(Address(RSP, 0), replacement);
// Move updated value into output register.
__ movups(replacement, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
break;
case MethodRecognizer::kFloat32x4WithY:
__ cvtsd2ss(replacement, replacement);
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
// Move value to stack.
__ movups(Address(RSP, 0), value);
// Write over Y value.
__ movss(Address(RSP, 4), replacement);
// Move updated value into output register.
__ movups(replacement, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
break;
case MethodRecognizer::kFloat32x4WithZ:
__ cvtsd2ss(replacement, replacement);
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
// Move value to stack.
__ movups(Address(RSP, 0), value);
// Write over Z value.
__ movss(Address(RSP, 8), replacement);
// Move updated value into output register.
__ movups(replacement, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
break;
case MethodRecognizer::kFloat32x4WithW:
__ cvtsd2ss(replacement, replacement);
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
// Move value to stack.
__ movups(Address(RSP, 0), value);
// Write over W value.
__ movss(Address(RSP, 12), replacement);
// Move updated value into output register.
__ movups(replacement, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
break;
default: UNREACHABLE();
}
@@ -4309,13 +4316,13 @@
Register v2 = locs()->in(2).reg();
Register v3 = locs()->in(3).reg();
XmmRegister result = locs()->out(0).fpu_reg();
- __ AddImmediate(RSP, Immediate(-4 * kInt32Size), PP);
+ __ AddImmediate(RSP, Immediate(-4 * kInt32Size));
__ movl(Address(RSP, 0 * kInt32Size), v0);
__ movl(Address(RSP, 1 * kInt32Size), v1);
__ movl(Address(RSP, 2 * kInt32Size), v2);
__ movl(Address(RSP, 3 * kInt32Size), v3);
__ movups(result, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(4 * kInt32Size), PP);
+ __ AddImmediate(RSP, Immediate(4 * kInt32Size));
}
@@ -4346,46 +4353,46 @@
Label y_false, y_done;
Label z_false, z_done;
Label w_false, w_done;
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
- __ CompareObject(v0, Bool::True(), PP);
+ __ CompareObject(v0, Bool::True());
__ j(NOT_EQUAL, &x_false);
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ jmp(&x_done);
__ Bind(&x_false);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ Bind(&x_done);
__ movl(Address(RSP, 0), temp);
- __ CompareObject(v1, Bool::True(), PP);
+ __ CompareObject(v1, Bool::True());
__ j(NOT_EQUAL, &y_false);
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ jmp(&y_done);
__ Bind(&y_false);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ Bind(&y_done);
__ movl(Address(RSP, 4), temp);
- __ CompareObject(v2, Bool::True(), PP);
+ __ CompareObject(v2, Bool::True());
__ j(NOT_EQUAL, &z_false);
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ jmp(&z_done);
__ Bind(&z_false);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ Bind(&z_done);
__ movl(Address(RSP, 8), temp);
- __ CompareObject(v3, Bool::True(), PP);
+ __ CompareObject(v3, Bool::True());
__ j(NOT_EQUAL, &w_false);
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ jmp(&w_done);
__ Bind(&w_false);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ Bind(&w_done);
__ movl(Address(RSP, 12), temp);
__ movups(result, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
}
@@ -4406,7 +4413,7 @@
Register result = locs()->out(0).reg();
Label done;
Label non_zero;
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
// Move value to stack.
__ movups(Address(RSP, 0), value);
switch (op_kind()) {
@@ -4424,13 +4431,13 @@
break;
default: UNREACHABLE();
}
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
__ testl(result, result);
__ j(NOT_ZERO, &non_zero, Assembler::kNearJump);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ jmp(&done);
__ Bind(&non_zero);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -4489,43 +4496,43 @@
Register flag = locs()->in(1).reg();
Register temp = locs()->temp(0).reg();
ASSERT(mask == locs()->out(0).fpu_reg());
- __ AddImmediate(RSP, Immediate(-16), PP);
+ __ AddImmediate(RSP, Immediate(-16));
// Copy mask to stack.
__ movups(Address(RSP, 0), mask);
Label falsePath, exitPath;
- __ CompareObject(flag, Bool::True(), PP);
+ __ CompareObject(flag, Bool::True());
__ j(NOT_EQUAL, &falsePath);
switch (op_kind()) {
case MethodRecognizer::kInt32x4WithFlagX:
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ movl(Address(RSP, 0), temp);
__ jmp(&exitPath);
__ Bind(&falsePath);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ movl(Address(RSP, 0), temp);
break;
case MethodRecognizer::kInt32x4WithFlagY:
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ movl(Address(RSP, 4), temp);
__ jmp(&exitPath);
__ Bind(&falsePath);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ movl(Address(RSP, 4), temp);
break;
case MethodRecognizer::kInt32x4WithFlagZ:
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ movl(Address(RSP, 8), temp);
__ jmp(&exitPath);
__ Bind(&falsePath);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ movl(Address(RSP, 8), temp);
break;
case MethodRecognizer::kInt32x4WithFlagW:
- __ LoadImmediate(temp, Immediate(0xFFFFFFFF), PP);
+ __ LoadImmediate(temp, Immediate(0xFFFFFFFF));
__ movl(Address(RSP, 12), temp);
__ jmp(&exitPath);
__ Bind(&falsePath);
- __ LoadImmediate(temp, Immediate(0x0), PP);
+ __ LoadImmediate(temp, Immediate(0x0));
__ movl(Address(RSP, 12), temp);
break;
default: UNREACHABLE();
@@ -4533,7 +4540,7 @@
__ Bind(&exitPath);
// Copy mask back to register.
__ movups(mask, Address(RSP, 0));
- __ AddImmediate(RSP, Immediate(16), PP);
+ __ AddImmediate(RSP, Immediate(16));
}
@@ -4708,7 +4715,7 @@
case Token::kBIT_NOT:
__ notq(value);
// Remove inverted smi-tag.
- __ AndImmediate(value, Immediate(~kSmiTagMask), PP);
+ __ AndImmediate(value, Immediate(~kSmiTagMask));
break;
default:
UNREACHABLE();
@@ -4785,7 +4792,7 @@
__ Bind(&returns_nan);
static double kNaN = NAN;
- __ LoadImmediate(temp, Immediate(reinterpret_cast<intptr_t>(&kNaN)), PP);
+ __ LoadImmediate(temp, Immediate(reinterpret_cast<intptr_t>(&kNaN)));
__ movsd(result, Address(temp, 0));
__ jmp(&done, Assembler::kNearJump);
@@ -5086,7 +5093,7 @@
locs->temp(InvokeMathCFunctionInstr::kDoubleTempIndex).fpu_reg();
__ xorps(zero_temp, zero_temp);
- __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1)), PP);
+ __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1)));
__ movsd(result, FieldAddress(temp, Double::value_offset()));
Label check_base, skip_call;
@@ -5101,14 +5108,14 @@
__ j(EQUAL, &return_base, Assembler::kNearJump);
// exponent == 2.0 ?
- __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(2.0)), PP);
+ __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(2.0)));
__ movsd(XMM0, FieldAddress(temp, Double::value_offset()));
__ comisd(exp, XMM0);
Label return_base_times_2;
__ j(EQUAL, &return_base_times_2, Assembler::kNearJump);
// exponent == 3.0 ?
- __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(3.0)), PP);
+ __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(3.0)));
__ movsd(XMM0, FieldAddress(temp, Double::value_offset()));
__ comisd(exp, XMM0);
__ j(NOT_EQUAL, &check_base);
@@ -5143,7 +5150,7 @@
__ j(PARITY_ODD, &try_sqrt, Assembler::kNearJump);
// Return NaN.
__ Bind(&return_nan);
- __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(NAN)), PP);
+ __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(NAN)));
__ movsd(result, FieldAddress(temp, Double::value_offset()));
__ jmp(&skip_call);
@@ -5151,14 +5158,14 @@
__ Bind(&try_sqrt);
// Before calling pow, check if we could use sqrt instead of pow.
__ LoadObject(temp,
- Double::ZoneHandle(Double::NewCanonical(kNegInfinity)), PP);
+ Double::ZoneHandle(Double::NewCanonical(kNegInfinity)));
__ movsd(result, FieldAddress(temp, Double::value_offset()));
// base == -Infinity -> call pow;
__ comisd(base, result);
__ j(EQUAL, &do_pow, Assembler::kNearJump);
// exponent == 0.5 ?
- __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0.5)), PP);
+ __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0.5)));
__ movsd(result, FieldAddress(temp, Double::value_offset()));
__ comisd(exp, result);
__ j(NOT_EQUAL, &do_pow, Assembler::kNearJump);
@@ -5355,7 +5362,7 @@
__ idivq(right); // RAX: quotient, RDX: remainder.
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
- __ CompareImmediate(RAX, Immediate(0x4000000000000000), PP);
+ __ CompareImmediate(RAX, Immediate(0x4000000000000000));
__ j(EQUAL, deopt);
__ Bind(&done);
@@ -5479,7 +5486,7 @@
licm_hoisted_ ? ICData::kHoisted : 0);
if (IsNullCheck()) {
__ CompareObject(locs()->in(0).reg(),
- Object::null_object(), PP);
+ Object::null_object());
Condition cond = DeoptIfNull() ? EQUAL : NOT_EQUAL;
__ j(cond, deopt);
return;
@@ -5574,7 +5581,7 @@
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
- __ CompareImmediate(value, Immediate(Smi::RawValue(cid_)), PP);
+ __ CompareImmediate(value, Immediate(Smi::RawValue(cid_)));
__ j(NOT_ZERO, deopt);
}
@@ -5616,7 +5623,7 @@
Register length = length_loc.reg();
const Smi& index = Smi::Cast(index_loc.constant());
__ CompareImmediate(
- length, Immediate(reinterpret_cast<int64_t>(index.raw())), PP);
+ length, Immediate(reinterpret_cast<int64_t>(index.raw())));
__ j(BELOW_EQUAL, deopt);
} else if (length_loc.IsConstant()) {
const Smi& length = Smi::Cast(length_loc.constant());
@@ -5626,7 +5633,7 @@
__ j(NEGATIVE, deopt);
} else {
__ CompareImmediate(
- index, Immediate(reinterpret_cast<int64_t>(length.raw())), PP);
+ index, Immediate(reinterpret_cast<int64_t>(length.raw())));
__ j(ABOVE_EQUAL, deopt);
}
} else {
@@ -6283,10 +6290,10 @@
Register result = locs()->out(0).reg();
Label done;
__ Bind(&is_false);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ jmp(&done);
__ Bind(&is_true);
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ Bind(&done);
}
@@ -6319,7 +6326,7 @@
const Array& arguments_descriptor =
Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
argument_names()));
- __ LoadObject(R10, arguments_descriptor, PP);
+ __ LoadObject(R10, arguments_descriptor);
// Function in RAX.
ASSERT(locs()->in(0).reg() == RAX);
@@ -6362,10 +6369,10 @@
Register result = locs()->out(0).reg();
Label done;
- __ LoadObject(result, Bool::True(), PP);
+ __ LoadObject(result, Bool::True());
__ CompareRegisters(result, value);
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
- __ LoadObject(result, Bool::False(), PP);
+ __ LoadObject(result, Bool::False());
__ Bind(&done);
}
@@ -6378,12 +6385,11 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Isolate* isolate = compiler->isolate();
- StubCode* stub_code = isolate->stub_code();
const Code& stub = Code::Handle(isolate,
- stub_code->GetAllocationStubForClass(cls()));
- const ExternalLabel label(stub.EntryPoint());
+ StubCode::GetAllocationStubForClass(cls()));
+ const StubEntry stub_entry(stub);
compiler->GenerateCall(token_pos(),
- &label,
+ stub_entry,
RawPcDescriptors::kOther,
locs());
compiler->AddStubCallTarget(stub);
@@ -6393,9 +6399,7 @@
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- StubCode* stub_code = compiler->isolate()->stub_code();
- const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
- __ CallPatchable(&label);
+ __ CallPatchable(*StubCode::DebugStepCheck_entry());
compiler->AddCurrentDescriptor(stub_kind_, Isolate::kNoDeoptId, token_pos());
compiler->RecordSafepoint(locs());
}
@@ -6416,7 +6420,7 @@
void GrowRegExpStackInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register typed_data = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ pushq(typed_data);
compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position.
deopt_id(),
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index a5b73df..70ce883 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -189,7 +189,8 @@
#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); \
+ __ MaybeTraceAllocation(cid, R2, &fall_through, \
+ /* inline_isolate = */ false); \
__ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* R2: requested array length argument. */ \
@@ -206,10 +207,9 @@
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
__ AddImmediate(R2, fixed_size); \
__ bic(R2, R2, Operand(kObjectAlignment - 1)); \
- Heap* heap = Isolate::Current()->heap(); \
- Heap::Space space = heap->SpaceForAllocation(cid); \
- __ LoadImmediate(R0, heap->TopAddress(space)); \
- __ ldr(R0, Address(R0, 0)); \
+ Heap::Space space = Heap::SpaceForAllocation(cid); \
+ __ ldr(R3, Address(THR, Thread::heap_offset())); \
+ __ ldr(R0, Address(R3, Heap::TopOffset(space))); \
\
/* R2: allocation size. */ \
__ adds(R1, R0, Operand(R2)); \
@@ -219,16 +219,15 @@
/* R0: potential new object start. */ \
/* R1: potential next object start. */ \
/* R2: allocation size. */ \
- __ LoadImmediate(R3, heap->EndAddress(space)); \
- __ ldr(R3, Address(R3, 0)); \
- __ cmp(R1, Operand(R3)); \
+ /* R3: heap. */ \
+ __ ldr(IP, Address(R3, Heap::EndOffset(space))); \
+ __ cmp(R1, Operand(IP)); \
__ b(&fall_through, CS); \
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ LoadAllocationStatsAddress(R4, cid); \
- __ LoadImmediate(R3, heap->TopAddress(space)); \
- __ str(R1, Address(R3, 0)); \
+ __ LoadAllocationStatsAddress(R4, cid, /* inline_isolate = */ false); \
+ __ str(R1, Address(R3, Heap::TopOffset(space))); \
__ AddImmediate(R0, kHeapObjectTag); \
/* Initialize the tags. */ \
/* R0: new object start as a tagged pointer. */ \
@@ -1661,8 +1660,14 @@
__ ldrb(R1, Address(R0, R1));
__ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols);
__ b(&fall_through, GE);
- __ LoadImmediate(R0,
- reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ const ExternalLabel symbols_label(
+ reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ Push(PP);
+ __ LoadPoolPointer();
+ assembler->set_constant_pool_allowed(true);
+ __ LoadExternalLabel(R0, &symbols_label, kNotPatchable);
+ assembler->set_constant_pool_allowed(false);
+ __ Pop(PP);
__ AddImmediate(R0, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ ldr(R0, Address(R0, R1, LSL, 2));
__ Ret();
@@ -1675,8 +1680,12 @@
__ ldrh(R1, Address(R0, R1));
__ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols);
__ b(&fall_through, GE);
- __ LoadImmediate(R0,
- reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ Push(PP);
+ __ LoadPoolPointer();
+ assembler->set_constant_pool_allowed(true);
+ __ LoadExternalLabel(R0, &symbols_label, kNotPatchable);
+ assembler->set_constant_pool_allowed(false);
+ __ Pop(PP);
__ AddImmediate(R0, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ ldr(R0, Address(R0, R1, LSL, 2));
__ Ret();
@@ -1771,12 +1780,10 @@
__ AddImmediate(length_reg, fixed_size);
__ bic(length_reg, length_reg, Operand(kObjectAlignment - 1));
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
const intptr_t cid = kOneByteStringCid;
- Heap::Space space = heap->SpaceForAllocation(cid);
- __ LoadImmediate(R3, heap->TopAddress(space));
- __ ldr(R0, Address(R3, 0));
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ __ ldr(R3, Address(THR, Thread::heap_offset()));
+ __ ldr(R0, Address(R3, Heap::TopOffset(space)));
// length_reg: allocation size.
__ adds(R1, R0, Operand(length_reg));
@@ -1786,16 +1793,15 @@
// R0: potential new object start.
// R1: potential next object start.
// R2: allocation size.
- // R3: heap->TopAddress(space).
- __ LoadImmediate(R7, heap->EndAddress(space));
- __ ldr(R7, Address(R7, 0));
+ // R3: heap.
+ __ ldr(R7, Address(R3, Heap::EndOffset(space)));
__ cmp(R1, Operand(R7));
__ b(&fail, CS);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ LoadAllocationStatsAddress(R4, cid);
- __ str(R1, Address(R3, 0));
+ __ LoadAllocationStatsAddress(R4, cid, /* inline_isolate = */ false);
+ __ str(R1, Address(R3, Heap::TopOffset(space)));
__ AddImmediate(R0, kHeapObjectTag);
// Initialize the tags.
@@ -2030,8 +2036,7 @@
// On stack: user tag (+0).
void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) {
// R1: Isolate.
- Isolate* isolate = Isolate::Current();
- __ LoadImmediate(R1, reinterpret_cast<uword>(isolate));
+ __ LoadIsolate(R1);
// R0: Current user tag.
__ ldr(R0, Address(R1, Isolate::current_tag_offset()));
// R2: UserTag.
@@ -2047,21 +2052,15 @@
void Intrinsifier::UserTag_defaultTag(Assembler* assembler) {
- Isolate* isolate = Isolate::Current();
- // Set return value to default tag address.
- __ LoadImmediate(R0,
- reinterpret_cast<uword>(isolate) + Isolate::default_tag_offset());
- __ ldr(R0, Address(R0, 0));
+ __ LoadIsolate(R0);
+ __ ldr(R0, Address(R0, Isolate::default_tag_offset()));
__ Ret();
}
void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) {
- // R1: Default tag address.
- Isolate* isolate = Isolate::Current();
- __ LoadImmediate(R1, reinterpret_cast<uword>(isolate));
- // Set return value to Isolate::current_tag_.
- __ ldr(R0, Address(R1, Isolate::current_tag_offset()));
+ __ LoadIsolate(R0);
+ __ ldr(R0, Address(R0, Isolate::current_tag_offset()));
__ Ret();
}
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 8cbb1ba..4d27700 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -58,28 +58,28 @@
__ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
// Null value is valid for any type.
- __ CompareObject(R2, Object::null_object(), PP);
+ __ CompareObject(R2, Object::null_object());
__ b(&checked_ok, EQ);
__ ldr(R1, Address(SP, 2 * kWordSize)); // Array.
__ ldr(R1, FieldAddress(R1, type_args_field_offset));
// R1: Type arguments of array.
- __ CompareObject(R1, Object::null_object(), PP);
+ __ CompareObject(R1, Object::null_object());
__ b(&checked_ok, EQ);
// Check if it's dynamic.
// Get type at index 0.
__ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
- __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()), PP);
+ __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
__ b(&checked_ok, EQ);
// Check for int and num.
__ tsti(R2, Immediate(Immediate(kSmiTagMask))); // Value is Smi?
__ b(&fall_through, NE); // Non-smi value.
- __ CompareObject(R0, Type::ZoneHandle(Type::IntType()), PP);
+ __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
__ b(&checked_ok, EQ);
- __ CompareObject(R0, Type::ZoneHandle(Type::Number()), PP);
+ __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
__ b(&fall_through, NE);
__ Bind(&checked_ok);
}
@@ -119,7 +119,7 @@
// Try allocating in new space.
const Class& cls = Class::Handle(
Isolate::Current()->object_store()->growable_object_array_class());
- __ TryAllocate(cls, &fall_through, R0, R1, kNoPP);
+ __ TryAllocate(cls, &fall_through, R0, R1);
// Store backing array object in growable array object.
__ ldr(R1, Address(SP, kArrayOffset)); // Data argument.
@@ -138,7 +138,7 @@
R1);
// Set the length field in the growable array object to 0.
- __ LoadImmediate(R1, 0, kNoPP);
+ __ LoadImmediate(R1, 0);
__ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
__ ret(); // Returns the newly allocated object in R0.
@@ -176,7 +176,7 @@
__ StoreIntoObject(R2,
FieldAddress(R1, Array::data_offset()),
R0);
- __ LoadObject(R0, Object::null_object(), PP);
+ __ LoadObject(R0, Object::null_object());
__ ret();
__ Bind(&fall_through);
}
@@ -198,7 +198,8 @@
#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
Label fall_through; \
const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
- __ MaybeTraceAllocation(cid, R2, kNoPP, &fall_through); \
+ __ MaybeTraceAllocation(cid, R2, &fall_through, \
+ /* inline_isolate = */ false); \
__ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* R2: requested array length argument. */ \
@@ -209,16 +210,15 @@
__ SmiUntag(R2); \
/* Check for maximum allowed length. */ \
/* R2: untagged array length. */ \
- __ CompareImmediate(R2, max_len, kNoPP); \
+ __ CompareImmediate(R2, max_len); \
__ b(&fall_through, GT); \
__ LslImmediate(R2, R2, scale_shift); \
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
- __ AddImmediate(R2, R2, fixed_size, kNoPP); \
+ __ AddImmediate(R2, R2, fixed_size); \
__ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \
- Heap* heap = Isolate::Current()->heap(); \
- Heap::Space space = heap->SpaceForAllocation(cid); \
- __ LoadImmediate(R0, heap->TopAddress(space), kNoPP); \
- __ ldr(R0, Address(R0, 0)); \
+ Heap::Space space = Heap::SpaceForAllocation(cid); \
+ __ ldr(R3, Address(THR, Thread::heap_offset())); \
+ __ ldr(R0, Address(R3, Heap::TopOffset(space))); \
\
/* R2: allocation size. */ \
__ adds(R1, R0, Operand(R2)); \
@@ -228,28 +228,28 @@
/* R0: potential new object start. */ \
/* R1: potential next object start. */ \
/* R2: allocation size. */ \
- __ LoadImmediate(R3, heap->EndAddress(space), kNoPP); \
- __ ldr(R3, Address(R3, 0)); \
- __ cmp(R1, Operand(R3)); \
+ /* R3: heap. */ \
+ __ ldr(R4, Address(R3, Heap::EndOffset(space))); \
+ __ cmp(R1, Operand(R4)); \
__ b(&fall_through, CS); \
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ LoadImmediate(R3, heap->TopAddress(space), kNoPP); \
- __ str(R1, Address(R3, 0)); \
- __ AddImmediate(R0, R0, kHeapObjectTag, kNoPP); \
- __ UpdateAllocationStatsWithSize(cid, R2, kNoPP, space); \
+ __ str(R1, Address(R3, Heap::TopOffset(space))); \
+ __ AddImmediate(R0, R0, kHeapObjectTag); \
+ __ UpdateAllocationStatsWithSize(cid, R2, space, \
+ /* inline_isolate = */ false); \
/* Initialize the tags. */ \
/* R0: new object start as a tagged pointer. */ \
/* R1: new object end address. */ \
/* R2: allocation size. */ \
{ \
- __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag, kNoPP); \
+ __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); \
__ LslImmediate(R2, R2, RawObject::kSizeTagPos - kObjectAlignmentLog2); \
__ csel(R2, ZR, R2, HI); \
\
/* Get the class index and insert it into the tags. */ \
- __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid), kNoPP); \
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); \
__ orr(R2, R2, Operand(TMP)); \
__ str(R2, FieldAddress(R0, type_name::tags_offset())); /* Tags. */ \
} \
@@ -267,7 +267,7 @@
/* R3: scratch register. */ \
/* data area to be initialized. */ \
__ mov(R3, ZR); \
- __ AddImmediate(R2, R0, sizeof(Raw##type_name) - 1, kNoPP); \
+ __ AddImmediate(R2, R0, sizeof(Raw##type_name) - 1); \
Label init_loop, done; \
__ Bind(&init_loop); \
__ cmp(R2, Operand(R1)); \
@@ -473,7 +473,7 @@
// Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
// cannot tag the result.
- __ CompareImmediate(R0, 0x4000000000000000, kNoPP);
+ __ CompareImmediate(R0, 0x4000000000000000);
__ b(&fall_through, EQ);
__ SmiTag(R0); // Not equal. Okay to tag and return.
__ ret(); // Return.
@@ -547,7 +547,7 @@
TestBothArgumentsSmis(assembler, &fall_through);
__ CompareImmediate(
- right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP);
+ right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)));
__ b(&fall_through, CS);
// Left is not a constant.
@@ -570,8 +570,8 @@
TestBothArgumentsSmis(assembler, &fall_through);
// R0 contains the right argument, R1 the left.
__ CompareRegisters(R1, R0);
- __ LoadObject(R0, Bool::False(), PP);
- __ LoadObject(TMP, Bool::True(), PP);
+ __ LoadObject(R0, Bool::False());
+ __ LoadObject(TMP, Bool::True());
__ csel(R0, TMP, R0, true_condition);
__ ret();
__ Bind(&fall_through);
@@ -618,10 +618,10 @@
__ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks.
// Both arguments are smi, '===' is good enough.
- __ LoadObject(R0, Bool::False(), PP);
+ __ LoadObject(R0, Bool::False());
__ ret();
__ Bind(&true_label);
- __ LoadObject(R0, Bool::True(), PP);
+ __ LoadObject(R0, Bool::True());
__ ret();
// At least one of the arguments was not Smi.
@@ -635,20 +635,20 @@
// Note that an instance of Mint or Bigint never contains a value that can be
// represented by Smi.
- __ CompareClassId(R0, kDoubleCid, kNoPP);
+ __ CompareClassId(R0, kDoubleCid);
__ b(&fall_through, EQ);
- __ LoadObject(R0, Bool::False(), PP); // Smi == Mint -> false.
+ __ LoadObject(R0, Bool::False()); // Smi == Mint -> false.
__ ret();
__ Bind(&receiver_not_smi);
// R1: receiver.
- __ CompareClassId(R1, kMintCid, kNoPP);
+ __ CompareClassId(R1, kMintCid);
__ b(&fall_through, NE);
// Receiver is Mint, return false if right is Smi.
__ tsti(R0, Immediate(kSmiTagMask));
__ b(&fall_through, NE);
- __ LoadObject(R0, Bool::False(), PP);
+ __ LoadObject(R0, Bool::False());
__ ret();
// TODO(srdjan): Implement Mint == Mint comparison.
@@ -673,7 +673,7 @@
__ b(&fall_through, LT);
// If shift amount is bigger than 63, set to 63.
- __ LoadImmediate(TMP, 0x3F, kNoPP);
+ __ LoadImmediate(TMP, 0x3F);
__ CompareRegisters(R0, TMP);
__ csel(R0, TMP, R0, GT);
__ SmiUntag(R1);
@@ -698,7 +698,7 @@
// XOR with sign bit to complement bits if value is negative.
__ eor(R0, R0, Operand(R0, ASR, 63));
__ clz(R0, R0);
- __ LoadImmediate(R1, 64, kNoPP);
+ __ LoadImmediate(R1, 64);
__ sub(R0, R1, Operand(R0));
__ SmiTag(R0);
__ ret();
@@ -729,9 +729,9 @@
__ add(R0, R0, Operand(R2));
__ add(R8, R8, Operand(R0, LSL, 3));
// R3 = n % (2 * _DIGIT_BITS)
- __ AndImmediate(R3, R5, 63, kNoPP);
+ __ AndImmediate(R3, R5, 63);
// R2 = 64 - R3
- __ LoadImmediate(R2, 64, kNoPP);
+ __ LoadImmediate(R2, 64);
__ sub(R2, R2, Operand(R3));
__ mov(R1, ZR);
Label loop;
@@ -772,9 +772,9 @@
__ sub(R0, R2, Operand(R0));
__ add(R6, R8, Operand(R0, LSL, 3));
// R3 = n % (2*_DIGIT_BITS)
- __ AndImmediate(R3, R5, 63, kNoPP);
+ __ AndImmediate(R3, R5, 63);
// R2 = 64 - R3
- __ LoadImmediate(R2, 64, kNoPP);
+ __ LoadImmediate(R2, 64);
__ sub(R2, R2, Operand(R3));
// R1 = x_digits[n ~/ (2*_DIGIT_BITS)] >> (n % (2*_DIGIT_BITS))
__ ldr(R1, Address(R7, 2 * Bigint::kBytesPerDigit, Address::PostIndex));
@@ -854,7 +854,7 @@
__ Bind(&last_carry);
Label done;
__ b(&done, CC);
- __ LoadImmediate(R0, 1, kNoPP);
+ __ LoadImmediate(R0, 1);
__ str(R0, Address(R6, 0));
__ Bind(&done);
@@ -1029,7 +1029,7 @@
__ b(&propagate_carry_loop, CS);
__ Bind(&done);
- __ LoadImmediate(R0, Smi::RawValue(2), kNoPP); // Two digits processed.
+ __ LoadImmediate(R0, Smi::RawValue(2)); // Two digits processed.
__ ret();
}
@@ -1144,7 +1144,7 @@
__ stp(R6, R7, Address(R5, 0, Address::PairOffset));
__ Bind(&x_zero);
- __ LoadImmediate(R0, Smi::RawValue(2), kNoPP); // Two digits processed.
+ __ LoadImmediate(R0, Smi::RawValue(2)); // Two digits processed.
__ ret();
}
@@ -1318,7 +1318,7 @@
__ str(R0,
FieldAddress(R4, TypedData::data_offset() + 2*Bigint::kBytesPerDigit));
- __ LoadImmediate(R0, Smi::RawValue(2), kNoPP); // Two digits processed.
+ __ LoadImmediate(R0, Smi::RawValue(2)); // Two digits processed.
__ ret();
}
@@ -1353,7 +1353,7 @@
__ str(R0,
FieldAddress(R4, TypedData::data_offset() + 4*Bigint::kBytesPerDigit));
- __ LoadImmediate(R0, Smi::RawValue(2), kNoPP); // Two digits processed.
+ __ LoadImmediate(R0, Smi::RawValue(2)); // Two digits processed.
__ ret();
}
@@ -1367,7 +1367,7 @@
__ ldr(R0, Address(SP, 0 * kWordSize));
__ tsti(R0, Immediate(kSmiTagMask));
__ b(is_smi, EQ);
- __ CompareClassId(R0, kDoubleCid, kNoPP);
+ __ CompareClassId(R0, kDoubleCid);
__ b(not_double_smi, NE);
// Fall through with Double in R0.
}
@@ -1383,18 +1383,18 @@
TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
// Both arguments are double, right operand is in R0.
- __ LoadDFieldFromOffset(V1, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V1, R0, Double::value_offset());
__ Bind(&double_op);
__ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
- __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V0, R0, Double::value_offset());
__ fcmpd(V0, V1);
- __ LoadObject(R0, Bool::False(), PP);
+ __ LoadObject(R0, Bool::False());
// Return false if D0 or D1 was NaN before checking true condition.
__ b(¬_nan, VC);
__ ret();
__ Bind(¬_nan);
- __ LoadObject(TMP, Bool::True(), PP);
+ __ LoadObject(TMP, Bool::True());
__ csel(R0, TMP, R0, true_condition);
__ ret();
@@ -1438,9 +1438,9 @@
TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
// Both arguments are double, right operand is in R0.
- __ LoadDFieldFromOffset(V1, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V1, R0, Double::value_offset());
__ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
- __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V0, R0, Double::value_offset());
switch (kind) {
case Token::kADD: __ faddd(V0, V0, V1); break;
case Token::kSUB: __ fsubd(V0, V0, V1); break;
@@ -1450,8 +1450,8 @@
}
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
- __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP);
- __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ TryAllocate(double_class, &fall_through, R0, R1);
+ __ StoreDFieldToOffset(V0, R0, Double::value_offset());
__ ret();
__ Bind(&fall_through);
}
@@ -1488,12 +1488,12 @@
__ SmiUntag(R0);
__ scvtfdx(V1, R0);
__ ldr(R0, Address(SP, 1 * kWordSize));
- __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V0, R0, Double::value_offset());
__ fmuld(V0, V0, V1);
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
- __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP);
- __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ TryAllocate(double_class, &fall_through, R0, R1);
+ __ StoreDFieldToOffset(V0, R0, Double::value_offset());
__ ret();
__ Bind(&fall_through);
}
@@ -1510,8 +1510,8 @@
__ scvtfdx(V0, R0);
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
- __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP);
- __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ TryAllocate(double_class, &fall_through, R0, R1);
+ __ StoreDFieldToOffset(V0, R0, Double::value_offset());
__ ret();
__ Bind(&fall_through);
}
@@ -1520,10 +1520,10 @@
void Intrinsifier::Double_getIsNaN(Assembler* assembler) {
Label is_true;
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V0, R0, Double::value_offset());
__ fcmpd(V0, V0);
- __ LoadObject(TMP, Bool::False(), PP);
- __ LoadObject(R0, Bool::True(), PP);
+ __ LoadObject(TMP, Bool::False());
+ __ LoadObject(R0, Bool::True());
__ csel(R0, TMP, R0, VC);
__ ret();
}
@@ -1535,10 +1535,10 @@
Label is_false, is_true, is_zero;
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V0, R0, Double::value_offset());
__ fcmpdz(V0);
- __ LoadObject(true_reg, Bool::True(), PP);
- __ LoadObject(false_reg, Bool::False(), PP);
+ __ LoadObject(true_reg, Bool::True());
+ __ LoadObject(false_reg, Bool::False());
__ b(&is_false, VS); // NaN -> false.
__ b(&is_zero, EQ); // Check for negative zero.
__ b(&is_false, CS); // >= 0 -> false.
@@ -1563,7 +1563,7 @@
Label fall_through;
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V0, R0, Double::value_offset());
// Explicit NaN check, since ARM gives an FPU exception if you try to
// convert NaN to an int.
@@ -1573,7 +1573,7 @@
__ fcvtzds(R0, V0);
// Overflow is signaled with minint.
// Check for overflow and that it fits into Smi.
- __ CompareImmediate(R0, 0xC000000000000000, kNoPP);
+ __ CompareImmediate(R0, 0xC000000000000000);
__ b(&fall_through, MI);
__ SmiTag(R0);
__ ret();
@@ -1585,13 +1585,13 @@
Label fall_through, is_smi, double_op;
TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
// Argument is double and is in R0.
- __ LoadDFieldFromOffset(V1, R0, Double::value_offset(), kNoPP);
+ __ LoadDFieldFromOffset(V1, R0, Double::value_offset());
__ Bind(&double_op);
__ fsqrtd(V0, V1);
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
- __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP);
- __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP);
+ __ TryAllocate(double_class, &fall_through, R0, R1);
+ __ StoreDFieldToOffset(V0, R0, Double::value_offset());
__ ret();
__ Bind(&is_smi);
__ SmiUntag(R0);
@@ -1627,13 +1627,13 @@
const int64_t disp =
Instance::DataOffsetFor(kTypedDataUint32ArrayCid) - kHeapObjectTag;
- __ LoadImmediate(R0, a_int_value, kNoPP);
- __ LoadFromOffset(R2, R1, disp, kNoPP);
+ __ LoadImmediate(R0, a_int_value);
+ __ LoadFromOffset(R2, R1, disp);
__ LsrImmediate(R3, R2, 32);
__ andi(R2, R2, Immediate(0xffffffff));
__ mul(R2, R0, R2);
__ add(R2, R2, Operand(R3));
- __ StoreToOffset(R2, R1, disp, kNoPP);
+ __ StoreToOffset(R2, R1, disp);
__ ret();
}
@@ -1642,8 +1642,8 @@
__ ldr(R0, Address(SP, 0 * kWordSize));
__ ldr(R1, Address(SP, 1 * kWordSize));
__ cmp(R0, Operand(R1));
- __ LoadObject(R0, Bool::False(), PP);
- __ LoadObject(TMP, Bool::True(), PP);
+ __ LoadObject(R0, Bool::False());
+ __ LoadObject(TMP, Bool::True());
__ csel(R0, TMP, R0, EQ);
__ ret();
}
@@ -1654,18 +1654,18 @@
Label fall_through;
__ ldr(R0, Address(SP, 0 * kWordSize));
__ LoadClassIdMayBeSmi(R1, R0);
- __ LoadClassById(R2, R1, PP);
+ __ LoadClassById(R2, R1);
// R2: class of instance (R0).
__ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
- __ CompareObject(R3, Object::null_object(), PP);
+ __ CompareObject(R3, Object::null_object());
__ b(&fall_through, NE);
__ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
- __ CompareImmediate(R3, 0, kNoPP);
+ __ CompareImmediate(R3, 0);
__ b(&fall_through, NE);
__ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
- __ CompareObject(R0, Object::null_object(), PP);
+ __ CompareObject(R0, Object::null_object());
__ b(&fall_through, EQ);
__ ret();
@@ -1696,19 +1696,19 @@
__ ldr(R2, FieldAddress(R0, String::length_offset()));
__ cmp(R1, Operand(R2));
__ b(&fall_through, CS); // Runtime throws exception.
- __ CompareClassId(R0, kOneByteStringCid, kNoPP);
+ __ CompareClassId(R0, kOneByteStringCid);
__ b(&try_two_byte_string, NE);
__ SmiUntag(R1);
- __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag);
__ ldr(R0, Address(R0, R1), kUnsignedByte);
__ SmiTag(R0);
__ ret();
__ Bind(&try_two_byte_string);
- __ CompareClassId(R0, kTwoByteStringCid, kNoPP);
+ __ CompareClassId(R0, kTwoByteStringCid);
__ b(&fall_through, NE);
ASSERT(kSmiTagShift == 1);
- __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag);
__ ldr(R0, Address(R0, R1), kUnsignedHalfword);
__ SmiTag(R0);
__ ret();
@@ -1729,32 +1729,38 @@
__ cmp(R1, Operand(R2));
__ b(&fall_through, CS); // Runtime throws exception.
- __ CompareClassId(R0, kOneByteStringCid, kNoPP);
+ __ CompareClassId(R0, kOneByteStringCid);
__ b(&try_two_byte_string, NE);
__ SmiUntag(R1);
- __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag);
__ ldr(R1, Address(R0, R1), kUnsignedByte);
- __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols, kNoPP);
+ __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols);
__ b(&fall_through, GE);
- __ LoadImmediate(
- R0, reinterpret_cast<uword>(Symbols::PredefinedAddress()), kNoPP);
+ const ExternalLabel symbols_label(
+ reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ TagAndPushPP();
+ __ LoadPoolPointer();
+ __ LoadExternalLabel(R0, &symbols_label);
+ __ PopAndUntagPP();
__ AddImmediate(
- R0, R0, Symbols::kNullCharCodeSymbolOffset * kWordSize, kNoPP);
+ R0, R0, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ ldr(R0, Address(R0, R1, UXTX, Address::Scaled));
__ ret();
__ Bind(&try_two_byte_string);
- __ CompareClassId(R0, kTwoByteStringCid, kNoPP);
+ __ CompareClassId(R0, kTwoByteStringCid);
__ b(&fall_through, NE);
ASSERT(kSmiTagShift == 1);
- __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag);
__ ldr(R1, Address(R0, R1), kUnsignedHalfword);
- __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols, kNoPP);
+ __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols);
__ b(&fall_through, GE);
- __ LoadImmediate(
- R0, reinterpret_cast<uword>(Symbols::PredefinedAddress()), kNoPP);
+ __ TagAndPushPP();
+ __ LoadPoolPointer();
+ __ LoadExternalLabel(R0, &symbols_label);
+ __ PopAndUntagPP();
__ AddImmediate(
- R0, R0, Symbols::kNullCharCodeSymbolOffset * kWordSize, kNoPP);
+ R0, R0, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ ldr(R0, Address(R0, R1, UXTX, Address::Scaled));
__ ret();
@@ -1766,8 +1772,8 @@
__ ldr(R0, Address(SP, 0 * kWordSize));
__ ldr(R0, FieldAddress(R0, String::length_offset()));
__ cmp(R0, Operand(Smi::RawValue(0)));
- __ LoadObject(R0, Bool::True(), PP);
- __ LoadObject(TMP, Bool::False(), PP);
+ __ LoadObject(R0, Bool::True());
+ __ LoadObject(TMP, Bool::False());
__ csel(R0, TMP, R0, NE);
__ ret();
}
@@ -1791,7 +1797,7 @@
__ b(&done, EQ);
__ mov(R3, ZR);
- __ AddImmediate(R6, R1, OneByteString::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R6, R1, OneByteString::data_offset() - kHeapObjectTag);
// R1: Instance of OneByteString.
// R2: String length, untagged integer.
// R3: Loop counter, untagged integer.
@@ -1823,7 +1829,7 @@
__ addw(R0, R0, Operand(R0, LSL, 15));
// hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
__ AndImmediate(
- R0, R0, (static_cast<intptr_t>(1) << String::kHashBits) - 1, kNoPP);
+ R0, R0, (static_cast<intptr_t>(1) << String::kHashBits) - 1);
__ CompareRegisters(R0, ZR);
// return hash_ == 0 ? 1 : hash_;
__ Bind(&done);
@@ -1843,20 +1849,19 @@
Label* failure) {
const Register length_reg = R2;
Label fail;
- __ MaybeTraceAllocation(kOneByteStringCid, R0, kNoPP, failure);
+ __ MaybeTraceAllocation(kOneByteStringCid, R0, failure,
+ /* inline_isolate = */ false);
__ mov(R6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
- __ AddImmediate(length_reg, length_reg, fixed_size, kNoPP);
+ __ AddImmediate(length_reg, length_reg, fixed_size);
__ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1)));
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
const intptr_t cid = kOneByteStringCid;
- Heap::Space space = heap->SpaceForAllocation(cid);
- __ LoadImmediate(R3, heap->TopAddress(space), kNoPP);
- __ ldr(R0, Address(R3));
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ __ ldr(R3, Address(THR, Thread::heap_offset()));
+ __ ldr(R0, Address(R3, Heap::TopOffset(space)));
// length_reg: allocation size.
__ adds(R1, R0, Operand(length_reg));
@@ -1866,17 +1871,17 @@
// R0: potential new object start.
// R1: potential next object start.
// R2: allocation size.
- // R3: heap->TopAddress(space).
- __ LoadImmediate(R7, heap->EndAddress(space), kNoPP);
- __ ldr(R7, Address(R7));
+ // R3: heap.
+ __ ldr(R7, Address(R3, Heap::EndOffset(space)));
__ cmp(R1, Operand(R7));
__ b(&fail, CS);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ str(R1, Address(R3));
- __ AddImmediate(R0, R0, kHeapObjectTag, kNoPP);
- __ UpdateAllocationStatsWithSize(cid, R2, kNoPP, space);
+ __ str(R1, Address(R3, Heap::TopOffset(space)));
+ __ AddImmediate(R0, R0, kHeapObjectTag);
+ __ UpdateAllocationStatsWithSize(cid, R2, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// R0: new object start as a tagged pointer.
@@ -1885,13 +1890,13 @@
{
const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2;
- __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag, kNoPP);
+ __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
__ LslImmediate(R2, R2, shift);
__ csel(R2, R2, ZR, LS);
// Get the class index and insert it into the tags.
// R2: size and bit tags.
- __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid), kNoPP);
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid));
__ orr(R2, R2, Operand(TMP));
__ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags.
}
@@ -1936,7 +1941,7 @@
__ SmiUntag(R1);
__ add(R3, R3, Operand(R1));
// Calculate start address and untag (- 1).
- __ AddImmediate(R3, R3, OneByteString::data_offset() - 1, kNoPP);
+ __ AddImmediate(R3, R3, OneByteString::data_offset() - 1);
// R3: Start address to copy from (untagged).
// R1: Untagged start index.
@@ -1957,11 +1962,11 @@
__ mov(R7, R0);
__ Bind(&loop);
__ ldr(R1, Address(R6), kUnsignedByte);
- __ AddImmediate(R6, R6, 1, kNoPP);
+ __ AddImmediate(R6, R6, 1);
__ sub(R2, R2, Operand(1));
__ cmp(R2, Operand(0));
__ str(R1, FieldAddress(R7, OneByteString::data_offset()), kUnsignedByte);
- __ AddImmediate(R7, R7, 1, kNoPP);
+ __ AddImmediate(R7, R7, 1);
__ b(&loop, GT);
__ Bind(&done);
@@ -1976,7 +1981,7 @@
__ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString.
__ SmiUntag(R1);
__ SmiUntag(R2);
- __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag);
__ str(R2, Address(R3, R1), kUnsignedByte);
__ ret();
}
@@ -2008,7 +2013,7 @@
// Is other OneByteString?
__ tsti(R1, Immediate(kSmiTagMask));
__ b(&fall_through, EQ);
- __ CompareClassId(R1, string_cid, kNoPP);
+ __ CompareClassId(R1, string_cid);
__ b(&fall_through, NE);
// Have same length?
@@ -2023,23 +2028,23 @@
(string_cid == kTwoByteStringCid));
const intptr_t offset = (string_cid == kOneByteStringCid) ?
OneByteString::data_offset() : TwoByteString::data_offset();
- __ AddImmediate(R0, R0, offset - kHeapObjectTag, kNoPP);
- __ AddImmediate(R1, R1, offset - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R0, R0, offset - kHeapObjectTag);
+ __ AddImmediate(R1, R1, offset - kHeapObjectTag);
__ SmiUntag(R2);
__ Bind(&loop);
- __ AddImmediate(R2, R2, -1, kNoPP);
+ __ AddImmediate(R2, R2, -1);
__ CompareRegisters(R2, ZR);
__ b(&is_true, LT);
if (string_cid == kOneByteStringCid) {
__ ldr(R3, Address(R0), kUnsignedByte);
__ ldr(R4, Address(R1), kUnsignedByte);
- __ AddImmediate(R0, R0, 1, kNoPP);
- __ AddImmediate(R1, R1, 1, kNoPP);
+ __ AddImmediate(R0, R0, 1);
+ __ AddImmediate(R1, R1, 1);
} else if (string_cid == kTwoByteStringCid) {
__ ldr(R3, Address(R0), kUnsignedHalfword);
__ ldr(R4, Address(R1), kUnsignedHalfword);
- __ AddImmediate(R0, R0, 2, kNoPP);
- __ AddImmediate(R1, R1, 2, kNoPP);
+ __ AddImmediate(R0, R0, 2);
+ __ AddImmediate(R1, R1, 2);
} else {
UNIMPLEMENTED();
}
@@ -2048,11 +2053,11 @@
__ b(&loop);
__ Bind(&is_true);
- __ LoadObject(R0, Bool::True(), PP);
+ __ LoadObject(R0, Bool::True());
__ ret();
__ Bind(&is_false);
- __ LoadObject(R0, Bool::False(), PP);
+ __ LoadObject(R0, Bool::False());
__ ret();
__ Bind(&fall_through);
@@ -2085,20 +2090,20 @@
// string CIDs as well as stored function pointers are in sequence.
__ ldr(R2, Address(SP, kRegExpParamOffset));
__ ldr(R1, Address(SP, kStringParamOffset));
- __ LoadClassId(R1, R1, kNoPP);
- __ AddImmediate(R1, R1, -kOneByteStringCid, kNoPP);
+ __ LoadClassId(R1, R1);
+ __ AddImmediate(R1, R1, -kOneByteStringCid);
__ add(R1, R2, Operand(R1, LSL, kWordSizeLog2));
__ ldr(R0, FieldAddress(R1, JSRegExp::function_offset(kOneByteStringCid)));
// Registers are now set up for the lazy compile stub. It expects the function
// in R0, the argument descriptor in R4, and IC-Data in R5.
static const intptr_t arg_count = RegExpMacroAssembler::kParamCount;
- __ LoadObject(R4, Array::Handle(ArgumentsDescriptor::New(arg_count)), kNoPP);
+ __ LoadObject(R4, Array::Handle(ArgumentsDescriptor::New(arg_count)));
__ eor(R5, R5, Operand(R5));
// Tail-call the function.
__ ldr(R1, FieldAddress(R0, Function::instructions_offset()));
- __ AddImmediate(R1, R1, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R1, R1, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R1);
}
@@ -2106,8 +2111,7 @@
// On stack: user tag (+0).
void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) {
// R1: Isolate.
- Isolate* isolate = Isolate::Current();
- __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP);
+ __ LoadIsolate(R1);
// R0: Current user tag.
__ ldr(R0, Address(R1, Isolate::current_tag_offset()));
// R2: UserTag.
@@ -2123,22 +2127,15 @@
void Intrinsifier::UserTag_defaultTag(Assembler* assembler) {
- Isolate* isolate = Isolate::Current();
- // Set return value to default tag address.
- __ LoadImmediate(R0,
- reinterpret_cast<uword>(isolate) + Isolate::default_tag_offset(),
- kNoPP);
- __ ldr(R0, Address(R0));
+ __ LoadIsolate(R0);
+ __ ldr(R0, Address(R0, Isolate::default_tag_offset()));
__ ret();
}
void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) {
- // R1: Default tag address.
- Isolate* isolate = Isolate::Current();
- __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP);
- // Set return value to Isolate::current_tag_.
- __ ldr(R0, Address(R1, Isolate::current_tag_offset()));
+ __ LoadIsolate(R0);
+ __ ldr(R0, Address(R0, Isolate::current_tag_offset()));
__ ret();
}
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index f2bb256..11f93e6 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -186,7 +186,8 @@
#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); \
+ __ MaybeTraceAllocation(cid, EDI, &fall_through, false, \
+ /* inline_isolate = */ false); \
__ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* EDI: requested array length argument. */ \
@@ -209,9 +210,9 @@
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
__ leal(EDI, Address(EDI, scale_factor, fixed_size)); \
__ andl(EDI, Immediate(-kObjectAlignment)); \
- Heap* heap = Isolate::Current()->heap(); \
- Heap::Space space = heap->SpaceForAllocation(cid); \
- __ movl(EAX, Address::Absolute(heap->TopAddress(space))); \
+ Heap::Space space = Heap::SpaceForAllocation(cid); \
+ __ movl(ECX, Address(THR, Thread::heap_offset())); \
+ __ movl(EAX, Address(ECX, Heap::TopOffset(space))); \
__ movl(EBX, EAX); \
\
/* EDI: allocation size. */ \
@@ -222,14 +223,16 @@
/* EAX: potential new object start. */ \
/* EBX: potential next object start. */ \
/* EDI: allocation size. */ \
- __ cmpl(EBX, Address::Absolute(heap->EndAddress(space))); \
+ /* ECX: heap. */ \
+ __ cmpl(EBX, Address(ECX, Heap::EndOffset(space))); \
__ j(ABOVE_EQUAL, &fall_through); \
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ movl(Address::Absolute(heap->TopAddress(space)), EBX); \
+ __ movl(Address(ECX, Heap::TopOffset(space)), EBX); \
__ addl(EAX, Immediate(kHeapObjectTag)); \
- __ UpdateAllocationStatsWithSize(cid, EDI, kNoRegister, space); \
+ __ UpdateAllocationStatsWithSize(cid, EDI, ECX, space, \
+ /* inline_isolate = */ false); \
\
/* Initialize the tags. */ \
/* EAX: new object start as a tagged pointer. */ \
@@ -588,7 +591,7 @@
&fall_through,
Assembler::kNearJump,
EAX, // Result register.
- kNoRegister);
+ ECX); // temp
// EBX and EDI are not objects but integer values.
__ movl(FieldAddress(EAX, Mint::value_offset()), EBX);
__ movl(FieldAddress(EAX, Mint::value_offset() + kWordSize), EDI);
@@ -1869,7 +1872,8 @@
Label* ok,
Label* failure,
Register length_reg) {
- __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false);
+ __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false,
+ /* inline_isolate = */ false);
if (length_reg != EDI) {
__ movl(EDI, length_reg);
}
@@ -1880,11 +1884,10 @@
__ leal(EDI, Address(EDI, TIMES_1, fixed_size)); // EDI is untagged.
__ andl(EDI, Immediate(-kObjectAlignment));
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
const intptr_t cid = kOneByteStringCid;
- Heap::Space space = heap->SpaceForAllocation(cid);
- __ movl(EAX, Address::Absolute(heap->TopAddress(space)));
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ __ movl(ECX, Address(THR, Thread::heap_offset()));
+ __ movl(EAX, Address(ECX, Heap::TopOffset(space)));
__ movl(EBX, EAX);
// EDI: allocation size.
@@ -1895,15 +1898,17 @@
// EAX: potential new object start.
// EBX: potential next object start.
// EDI: allocation size.
- __ cmpl(EBX, Address::Absolute(heap->EndAddress(space)));
+ // ECX: heap.
+ __ cmpl(EBX, Address(ECX, Heap::EndOffset(space)));
__ j(ABOVE_EQUAL, &pop_and_fail);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ movl(Address::Absolute(heap->TopAddress(space)), EBX);
+ __ movl(Address(ECX, Heap::TopOffset(space)), EBX);
__ addl(EAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, EDI, kNoRegister, space);
+ __ UpdateAllocationStatsWithSize(cid, EDI, ECX, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// EAX: new object start as a tagged pointer.
@@ -2116,45 +2121,32 @@
// On stack: user tag (+1), return-address (+0).
void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) {
- Isolate* isolate = Isolate::Current();
- const Address current_tag_addr =
- Address::Absolute(reinterpret_cast<uword>(isolate) +
- Isolate::current_tag_offset());
- const Address user_tag_addr =
- Address::Absolute(reinterpret_cast<uword>(isolate) +
- Isolate::user_tag_offset());
+ // RDI: Isolate.
+ __ LoadIsolate(EDI);
// EAX: Current user tag.
- __ movl(EAX, current_tag_addr);
+ __ movl(EAX, Address(EDI, Isolate::current_tag_offset()));
// EAX: UserTag.
__ movl(EBX, Address(ESP, + 1 * kWordSize));
// Set Isolate::current_tag_.
- __ movl(current_tag_addr, EBX);
+ __ movl(Address(EDI, Isolate::current_tag_offset()), EBX);
// EAX: UserTag's tag.
__ movl(EBX, FieldAddress(EBX, UserTag::tag_offset()));
// Set Isolate::user_tag_.
- __ movl(user_tag_addr, EBX);
+ __ movl(Address(EDI, Isolate::user_tag_offset()), EBX);
__ ret();
}
void Intrinsifier::UserTag_defaultTag(Assembler* assembler) {
- Isolate* isolate = Isolate::Current();
- const Address default_tag_addr =
- Address::Absolute(
- reinterpret_cast<uword>(isolate) + Isolate::default_tag_offset());
- // Set return value.
- __ movl(EAX, default_tag_addr);
+ __ LoadIsolate(EAX);
+ __ movl(EAX, Address(EAX, Isolate::default_tag_offset()));
__ ret();
}
void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) {
- Isolate* isolate = Isolate::Current();
- const Address current_tag_addr =
- Address::Absolute(reinterpret_cast<uword>(isolate) +
- Isolate::current_tag_offset());
- // Set return value to Isolate::current_tag_.
- __ movl(EAX, current_tag_addr);
+ __ LoadIsolate(EAX);
+ __ movl(EAX, Address(EAX, Isolate::current_tag_offset()));
__ ret();
}
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 1cbb12f..d66ffb2 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -179,7 +179,8 @@
#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); \
+ __ MaybeTraceAllocation(cid, T2, &fall_through, \
+ /* inline_isolate = */ false); \
__ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* T2: requested array length argument. */ \
@@ -195,10 +196,9 @@
__ AddImmediate(T2, fixed_size); \
__ LoadImmediate(TMP, -kObjectAlignment); \
__ and_(T2, T2, TMP); \
- Heap* heap = Isolate::Current()->heap(); \
- Heap::Space space = heap->SpaceForAllocation(cid); \
- __ LoadImmediate(V0, heap->TopAddress(space)); \
- __ lw(V0, Address(V0, 0)); \
+ Heap::Space space = Heap::SpaceForAllocation(cid); \
+ __ lw(T3, Address(THR, Thread::heap_offset())); \
+ __ lw(V0, Address(T3, Heap::TopOffset(space))); \
\
/* T2: allocation size. */ \
__ addu(T1, V0, T2); \
@@ -209,16 +209,16 @@
/* V0: potential new object start. */ \
/* T1: potential next object start. */ \
/* T2: allocation size. */ \
- __ LoadImmediate(T3, heap->EndAddress(space)); \
- __ lw(T3, Address(T3, 0)); \
- __ BranchUnsignedGreaterEqual(T1, T3, &fall_through); \
+ /* T3: heap. */ \
+ __ lw(T4, Address(T3, Heap::EndOffset(space))); \
+ __ BranchUnsignedGreaterEqual(T1, T4, &fall_through); \
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ LoadImmediate(T3, heap->TopAddress(space)); \
- __ sw(T1, Address(T3, 0)); \
+ __ sw(T1, Address(T3, Heap::TopOffset(space))); \
__ AddImmediate(V0, kHeapObjectTag); \
- __ UpdateAllocationStatsWithSize(cid, T2, T4, space); \
+ __ UpdateAllocationStatsWithSize(cid, T2, T4, space, \
+ /* inline_isolate = */ false); \
/* Initialize the tags. */ \
/* V0: new object start as a tagged pointer. */ \
/* T1: new object end address. */ \
@@ -1767,8 +1767,16 @@
__ lbu(T2, FieldAddress(T2, OneByteString::data_offset()));
__ BranchUnsignedGreaterEqual(
T2, Immediate(Symbols::kNumberOfOneCharCodeSymbols), &fall_through);
- __ LoadImmediate(
- V0, reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ const ExternalLabel symbols_label(
+ reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ Push(PP);
+ __ Push(RA);
+ __ LoadPoolPointer();
+ assembler->set_constant_pool_allowed(true);
+ __ LoadExternalLabel(V0, &symbols_label, kNotPatchable);
+ assembler->set_constant_pool_allowed(false);
+ __ Pop(RA);
+ __ Pop(PP);
__ AddImmediate(V0, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ sll(T2, T2, 2);
__ addu(T2, T2, V0);
@@ -1782,8 +1790,14 @@
__ lhu(T2, FieldAddress(T2, TwoByteString::data_offset()));
__ BranchUnsignedGreaterEqual(
T2, Immediate(Symbols::kNumberOfOneCharCodeSymbols), &fall_through);
- __ LoadImmediate(V0,
- reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ Push(PP);
+ __ Push(RA);
+ __ LoadPoolPointer();
+ assembler->set_constant_pool_allowed(true);
+ __ LoadExternalLabel(V0, &symbols_label, kNotPatchable);
+ assembler->set_constant_pool_allowed(false);
+ __ Pop(RA);
+ __ Pop(PP);
__ AddImmediate(V0, Symbols::kNullCharCodeSymbolOffset * kWordSize);
__ sll(T2, T2, 2);
__ addu(T2, T2, V0);
@@ -1883,7 +1897,8 @@
Label* ok,
Label* failure) {
const Register length_reg = T2;
- __ MaybeTraceAllocation(kOneByteStringCid, V0, failure);
+ __ MaybeTraceAllocation(kOneByteStringCid, V0, failure,
+ /* inline_isolate = */ false);
__ mov(T6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);
@@ -1892,12 +1907,10 @@
__ LoadImmediate(TMP, ~(kObjectAlignment - 1));
__ and_(length_reg, length_reg, TMP);
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
const intptr_t cid = kOneByteStringCid;
- Heap::Space space = heap->SpaceForAllocation(cid);
- __ LoadImmediate(T3, heap->TopAddress(space));
- __ lw(V0, Address(T3, 0));
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ __ lw(T3, Address(THR, Thread::heap_offset()));
+ __ lw(V0, Address(T3, Heap::TopOffset(space)));
// length_reg: allocation size.
__ addu(T1, V0, length_reg);
@@ -1907,17 +1920,17 @@
// V0: potential new object start.
// T1: potential next object start.
// T2: allocation size.
- // T3: heap->TopAddress(space).
- __ LoadImmediate(T4, heap->EndAddress(space));
- __ lw(T4, Address(T4, 0));
+ // T3: heap.
+ __ lw(T4, Address(T3, Heap::EndOffset(space)));
__ BranchUnsignedGreaterEqual(T1, T4, failure);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ sw(T1, Address(T3, 0));
+ __ sw(T1, Address(T3, Heap::TopOffset(space)));
__ AddImmediate(V0, kHeapObjectTag);
- __ UpdateAllocationStatsWithSize(cid, T2, T3, space);
+ __ UpdateAllocationStatsWithSize(cid, T2, T3, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// V0: new object start as a tagged pointer.
@@ -2137,8 +2150,7 @@
// On stack: user tag (+0).
void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) {
// T1: Isolate.
- Isolate* isolate = Isolate::Current();
- __ LoadImmediate(T1, reinterpret_cast<uword>(isolate));
+ __ LoadIsolate(T1);
// V0: Current user tag.
__ lw(V0, Address(T1, Isolate::current_tag_offset()));
// T2: UserTag.
@@ -2155,20 +2167,14 @@
void Intrinsifier::UserTag_defaultTag(Assembler* assembler) {
- Isolate* isolate = Isolate::Current();
- // V0: Address of default tag.
- __ LoadImmediate(V0,
- reinterpret_cast<uword>(isolate) + Isolate::default_tag_offset());
+ __ LoadIsolate(V0);
__ Ret();
- __ delay_slot()->lw(V0, Address(V0, 0));
+ __ delay_slot()->lw(V0, Address(V0, Isolate::default_tag_offset()));
}
void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) {
- // V0: Isolate.
- Isolate* isolate = Isolate::Current();
- __ LoadImmediate(V0, reinterpret_cast<uword>(isolate));
- // Set return value.
+ __ LoadIsolate(V0);
__ Ret();
__ delay_slot()->lw(V0, Address(V0, Isolate::current_tag_offset()));
}
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 6ed3726..aeea84b 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -72,7 +72,7 @@
// Try allocating in new space.
const Class& cls = Class::Handle(
Isolate::Current()->object_store()->growable_object_array_class());
- __ TryAllocate(cls, &fall_through, Assembler::kFarJump, RAX, kNoRegister);
+ __ TryAllocate(cls, &fall_through, Assembler::kFarJump, RAX, R13);
// Store backing array object in growable array object.
__ movq(RCX, Address(RSP, kArrayOffset)); // data argument.
@@ -121,7 +121,7 @@
__ StoreIntoObject(RDX,
FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()),
RAX);
- __ LoadObject(RAX, Object::null_object(), PP);
+ __ LoadObject(RAX, Object::null_object());
__ ret();
__ Bind(&fall_through);
}
@@ -130,7 +130,8 @@
#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); \
+ __ MaybeTraceAllocation(cid, &fall_through, false, \
+ /* inline_isolate = */ false); \
__ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \
/* Check that length is a positive Smi. */ \
/* RDI: requested array length argument. */ \
@@ -153,10 +154,9 @@
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
__ leaq(RDI, Address(RDI, scale_factor, fixed_size)); \
__ andq(RDI, Immediate(-kObjectAlignment)); \
- Heap* heap = Isolate::Current()->heap(); \
- Heap::Space space = heap->SpaceForAllocation(cid); \
- __ movq(RAX, Immediate(heap->TopAddress(space))); \
- __ movq(RAX, Address(RAX, 0)); \
+ Heap::Space space = Heap::SpaceForAllocation(cid); \
+ __ movq(R13, Address(THR, Thread::heap_offset())); \
+ __ movq(RAX, Address(R13, Heap::TopOffset(space))); \
__ movq(RCX, RAX); \
\
/* RDI: allocation size. */ \
@@ -167,17 +167,16 @@
/* RAX: potential new object start. */ \
/* RCX: potential next object start. */ \
/* RDI: allocation size. */ \
- /* R13: scratch register. */ \
- __ movq(R13, Immediate(heap->EndAddress(space))); \
- __ cmpq(RCX, Address(R13, 0)); \
+ /* R13: heap. */ \
+ __ cmpq(RCX, Address(R13, Heap::EndOffset(space))); \
__ j(ABOVE_EQUAL, &fall_through); \
\
/* Successfully allocated the object(s), now update top to point to */ \
/* next object start and initialize the object. */ \
- __ movq(R13, Immediate(heap->TopAddress(space))); \
- __ movq(Address(R13, 0), RCX); \
+ __ movq(Address(R13, Heap::TopOffset(space)), RCX); \
__ addq(RAX, Immediate(kHeapObjectTag)); \
- __ UpdateAllocationStatsWithSize(cid, RDI, space); \
+ __ UpdateAllocationStatsWithSize(cid, RDI, space, \
+ /* inline_isolate = */ false); \
/* Initialize the tags. */ \
/* RAX: new object start as a tagged pointer. */ \
/* RCX: new object end address. */ \
@@ -583,10 +582,10 @@
// RAX contains the right argument.
__ cmpq(Address(RSP, + 2 * kWordSize), RAX);
__ j(true_condition, &true_label, Assembler::kNearJump);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&true_label);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
__ Bind(&fall_through);
}
@@ -633,10 +632,10 @@
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump);
// Both arguments are smi, '===' is good enough.
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&true_label);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
// At least one of the arguments was not Smi.
@@ -652,7 +651,7 @@
__ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize));
__ CompareClassId(RAX, kDoubleCid);
__ j(EQUAL, &fall_through);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&receiver_not_smi);
@@ -664,7 +663,7 @@
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through);
// Smi == Mint -> false.
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
// TODO(srdjan): Implement Mint == Mint comparison.
@@ -1262,10 +1261,10 @@
__ j(true_condition, &is_true, Assembler::kNearJump);
// Fall through false.
__ Bind(&is_false);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
__ Bind(&is_smi);
__ SmiUntag(RAX);
@@ -1322,7 +1321,7 @@
&fall_through,
Assembler::kFarJump,
RAX, // Result register.
- kNoRegister); // Pool pointer might not be loaded.
+ R13);
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
__ ret();
__ Bind(&fall_through);
@@ -1367,7 +1366,7 @@
&fall_through,
Assembler::kFarJump,
RAX, // Result register.
- kNoRegister); // Pool pointer might not be loaded.
+ R13);
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
__ ret();
__ Bind(&fall_through);
@@ -1389,7 +1388,7 @@
&fall_through,
Assembler::kFarJump,
RAX, // Result register.
- kNoRegister); // Pool pointer might not be loaded.
+ R13);
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
__ ret();
__ Bind(&fall_through);
@@ -1402,10 +1401,10 @@
__ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
__ comisd(XMM0, XMM0);
__ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true;
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
}
@@ -1420,10 +1419,10 @@
__ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero.
__ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false.
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
__ Bind(&is_false);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&is_zero);
// Check for negative zero (get the sign bit).
@@ -1463,7 +1462,7 @@
&fall_through,
Assembler::kFarJump,
RAX, // Result register.
- kNoRegister); // Pool pointer might not be loaded.
+ R13);
__ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
__ ret();
__ Bind(&is_smi);
@@ -1519,10 +1518,10 @@
__ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize));
__ cmpq(RAX, Address(RSP, + kReceiverOffset * kWordSize));
__ j(EQUAL, &is_true, Assembler::kNearJump);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
}
@@ -1534,17 +1533,17 @@
__ LoadClassIdMayBeSmi(RCX, RAX);
// RCX: untagged cid of instance (RAX).
- __ LoadClassById(RDI, RCX, PP);
+ __ LoadClassById(RDI, RCX);
// RDI: class of instance (RAX).
__ movq(RCX, FieldAddress(RDI, Class::signature_function_offset()));
- __ CompareObject(RCX, Object::null_object(), PP);
+ __ CompareObject(RCX, Object::null_object());
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
__ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
__ cmpq(RCX, Immediate(0));
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
__ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset()));
- __ CompareObject(RAX, Object::null_object(), PP);
+ __ CompareObject(RAX, Object::null_object());
__ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set.
__ ret();
@@ -1609,8 +1608,14 @@
__ movzxb(RCX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset()));
__ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols));
__ j(GREATER_EQUAL, &fall_through);
- __ movq(RAX,
- Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())));
+ const ExternalLabel symbols_label(
+ reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ pushq(PP);
+ __ LoadPoolPointer();
+ assembler->set_constant_pool_allowed(true);
+ __ LoadExternalLabel(RAX, &symbols_label, kNotPatchable);
+ assembler->set_constant_pool_allowed(false);
+ __ popq(PP);
__ movq(RAX, Address(RAX,
RCX,
TIMES_8,
@@ -1624,8 +1629,12 @@
__ movzxw(RCX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset()));
__ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols));
__ j(GREATER_EQUAL, &fall_through);
- __ movq(RAX,
- Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())));
+ __ pushq(PP);
+ __ LoadPoolPointer();
+ assembler->set_constant_pool_allowed(true);
+ __ LoadExternalLabel(RAX, &symbols_label, kNotPatchable);
+ assembler->set_constant_pool_allowed(false);
+ __ popq(PP);
__ movq(RAX, Address(RAX,
RCX,
TIMES_8,
@@ -1643,10 +1652,10 @@
__ movq(RAX, FieldAddress(RAX, String::length_offset()));
__ cmpq(RAX, Immediate(Smi::RawValue(0)));
__ j(EQUAL, &is_true, Assembler::kNearJump);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
}
@@ -1727,7 +1736,8 @@
Label* ok,
Label* failure,
Register length_reg) {
- __ MaybeTraceAllocation(kOneByteStringCid, failure, false);
+ __ MaybeTraceAllocation(kOneByteStringCid, failure, false,
+ /* inline_isolate = */ false);
if (length_reg != RDI) {
__ movq(RDI, length_reg);
}
@@ -1738,12 +1748,10 @@
__ leaq(RDI, Address(RDI, TIMES_1, fixed_size)); // RDI is a Smi.
__ andq(RDI, Immediate(-kObjectAlignment));
- Isolate* isolate = Isolate::Current();
- Heap* heap = isolate->heap();
const intptr_t cid = kOneByteStringCid;
- Heap::Space space = heap->SpaceForAllocation(cid);
- __ movq(RAX, Immediate(heap->TopAddress(space)));
- __ movq(RAX, Address(RAX, 0));
+ Heap::Space space = Heap::SpaceForAllocation(cid);
+ __ movq(R13, Address(THR, Thread::heap_offset()));
+ __ movq(RAX, Address(R13, Heap::TopOffset(space)));
// RDI: allocation size.
__ movq(RCX, RAX);
@@ -1754,16 +1762,16 @@
// RAX: potential new object start.
// RCX: potential next object start.
// RDI: allocation size.
- __ movq(R13, Immediate(heap->EndAddress(space)));
- __ cmpq(RCX, Address(R13, 0));
+ // R13: heap.
+ __ cmpq(RCX, Address(R13, Heap::EndOffset(space)));
__ j(ABOVE_EQUAL, &pop_and_fail);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ movq(R13, Immediate(heap->TopAddress(space)));
- __ movq(Address(R13, 0), RCX);
+ __ movq(Address(R13, Heap::TopOffset(space)), RCX);
__ addq(RAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, RDI, space);
+ __ UpdateAllocationStatsWithSize(cid, RDI, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// RAX: new object start as a tagged pointer.
@@ -1918,11 +1926,11 @@
__ jmp(&loop, Assembler::kNearJump);
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ ret();
__ Bind(&is_false);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ ret();
__ Bind(&fall_through);
@@ -1956,7 +1964,7 @@
__ movq(RBX, Address(RSP, kRegExpParamOffset));
__ movq(RDI, Address(RSP, kStringParamOffset));
__ LoadClassId(RDI, RDI);
- __ SubImmediate(RDI, Immediate(kOneByteStringCid), PP);
+ __ SubImmediate(RDI, Immediate(kOneByteStringCid));
__ movq(RAX, FieldAddress(RBX, RDI, TIMES_8,
JSRegExp::function_offset(kOneByteStringCid)));
@@ -1964,7 +1972,7 @@
// in RAX, the argument descriptor in R10, and IC-Data in RCX.
static const intptr_t arg_count = RegExpMacroAssembler::kParamCount;
__ LoadObject(R10,
- Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)), PP);
+ Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)));
__ xorq(RCX, RCX);
// Tail-call the function.
@@ -1977,10 +1985,7 @@
// On stack: user tag (+1), return-address (+0).
void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) {
// RBX: Isolate.
- Isolate* isolate = Isolate::Current();
- const Immediate& isolate_address =
- Immediate(reinterpret_cast<int64_t>(isolate));
- __ movq(RBX, isolate_address);
+ __ LoadIsolate(RBX);
// RAX: Current user tag.
__ movq(RAX, Address(RBX, Isolate::current_tag_offset()));
// R10: UserTag.
@@ -1996,26 +2001,15 @@
void Intrinsifier::UserTag_defaultTag(Assembler* assembler) {
- // RBX: Address of default tag.
- Isolate* isolate = Isolate::Current();
- const Immediate& default_tag_addr =
- Immediate(reinterpret_cast<int64_t>(isolate) +
- Isolate::default_tag_offset());
- __ movq(RBX, default_tag_addr);
- // Set return value.
- __ movq(RAX, Address(RBX, 0));
+ __ LoadIsolate(RAX);
+ __ movq(RAX, Address(RAX, Isolate::default_tag_offset()));
__ ret();
}
void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) {
- // RBX: Isolate.
- Isolate* isolate = Isolate::Current();
- const Immediate& isolate_address =
- Immediate(reinterpret_cast<int64_t>(isolate));
- __ movq(RBX, isolate_address);
- // Set return value to Isolate::current_tag_.
- __ movq(RAX, Address(RBX, Isolate::current_tag_offset()));
+ __ LoadIsolate(RAX);
+ __ movq(RAX, Address(RAX, Isolate::current_tag_offset()));
__ ret();
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 6c8d73f..764d21a 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -60,6 +60,14 @@
DEFINE_FLAG(charp, timeline_trace_dir, NULL,
"Enable all timeline trace streams and output traces "
"into specified directory.");
+DEFINE_FLAG(int, new_gen_semi_max_size, (kWordSize <= 4) ? 16 : 32,
+ "Max size of new gen semi space in MB");
+DEFINE_FLAG(int, old_gen_heap_size, 0,
+ "Max size of old gen heap size in MB, or 0 for unlimited,"
+ "e.g: --old_gen_heap_size=1024 allows up to 1024MB old gen heap");
+DEFINE_FLAG(int, external_max_size, (kWordSize <= 4) ? 512 : 1024,
+ "Max total size of external allocations in MB, or 0 for unlimited,"
+ "e.g: --external_max_size=1024 allows up to 1024MB of externals");
// TODO(iposva): Make these isolate specific flags inaccessible using the
// regular FLAG_xyz pattern.
@@ -608,7 +616,7 @@
void BaseIsolate::AssertCurrentThreadIsMutator() const {
ASSERT(Isolate::Current() == this);
- ASSERT(Isolate::Current()->mutator_thread() == Thread::Current());
+ ASSERT(Isolate::Current()->MutatorThreadIsCurrentThread());
}
#endif // defined(DEBUG)
@@ -642,7 +650,6 @@
environment_callback_(NULL),
library_tag_handler_(NULL),
api_state_(NULL),
- stub_code_(NULL),
debugger_(NULL),
single_step_(false),
resume_request_(false),
@@ -682,8 +689,10 @@
tag_table_(GrowableObjectArray::null()),
current_tag_(UserTag::null()),
default_tag_(UserTag::null()),
+ collected_closures_(GrowableObjectArray::null()),
deoptimized_code_array_(GrowableObjectArray::null()),
metrics_list_head_(NULL),
+ compilation_allowed_(true),
cha_(NULL),
next_(NULL),
pause_loop_monitor_(NULL),
@@ -705,7 +714,6 @@
delete heap_;
delete object_store_;
delete api_state_;
- delete stub_code_;
delete debugger_;
#if defined(USING_SIMULATOR)
delete simulator_;
@@ -765,6 +773,12 @@
ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT);
#undef ISOLATE_TIMELINE_STREAM_INIT
+ Heap::Init(result,
+ is_vm_isolate
+ ? 0 // New gen size 0; VM isolate should only allocate in old.
+ : FLAG_new_gen_semi_max_size * MBInWords,
+ FLAG_old_gen_heap_size * MBInWords,
+ FLAG_external_max_size * MBInWords);
// TODO(5411455): For now just set the recently created isolate as
// the current isolate.
@@ -830,8 +844,8 @@
uword Isolate::GetCurrentStackPointer() {
// 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.
- uword (*func)() =
- reinterpret_cast<uword (*)()>(StubCode::GetStackPointerEntryPoint());
+ uword (*func)() = reinterpret_cast<uword (*)()>(
+ StubCode::GetStackPointer_entry()->EntryPoint());
// But for performance (and to support simulators), we normally use a local.
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
@@ -1607,6 +1621,9 @@
// Visit the tag table which is stored in the isolate.
visitor->VisitPointer(reinterpret_cast<RawObject**>(&tag_table_));
+ // Visit array of closures pending precompilation.
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&collected_closures_));
+
// Visit the deoptimized code array which is stored in the isolate.
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&deoptimized_code_array_));
@@ -1807,6 +1824,11 @@
}
+void Isolate::set_collected_closures(const GrowableObjectArray& value) {
+ collected_closures_ = value.raw();
+}
+
+
void Isolate::set_deoptimized_code_array(const GrowableObjectArray& value) {
deoptimized_code_array_ = value.raw();
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index a7aa4fc..c43a3fa 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -122,12 +122,6 @@
return thread == NULL ? NULL : thread->isolate();
}
- static void InitOnce();
- static Isolate* Init(const char* name_prefix,
- const Dart_IsolateFlags& api_flags,
- bool is_vm_isolate = false);
- void Shutdown();
-
// Register a newly introduced class.
void RegisterClass(const Class& cls);
void RegisterClassAt(intptr_t index, const Class& cls);
@@ -163,16 +157,15 @@
message_notify_callback_ = value;
}
- // A thread that operates on this isolate and may execute Dart code.
- // No other threads operating on this isolate may execute Dart code.
- // TODO(koda): Remove after pivoting to thread in NativeArguments.
- Thread* mutator_thread() {
- DEBUG_ASSERT(mutator_thread_ == NULL || IsIsolateOf(mutator_thread_));
- return mutator_thread_;
+ // Limited public access to BaseIsolate::mutator_thread_ for code that
+ // must treat the mutator as the default or a special case. Prefer code
+ // that works uniformly across all threads.
+ bool HasMutatorThread() {
+ return mutator_thread_ != NULL;
}
-#if defined(DEBUG)
- bool IsIsolateOf(Thread* thread);
-#endif // DEBUG
+ bool MutatorThreadIsCurrentThread() {
+ return mutator_thread_ == Thread::Current();
+ }
const char* name() const { return name_; }
const char* debugger_name() const { return debugger_name_; }
@@ -244,9 +237,6 @@
ApiState* api_state() const { return api_state_; }
void set_api_state(ApiState* value) { api_state_ = value; }
- StubCode* stub_code() const { return stub_code_; }
- void set_stub_code(StubCode* value) { stub_code_ = value; }
-
LongJumpScope* long_jump_base() const { return long_jump_base_; }
void set_long_jump_base(LongJumpScope* value) { long_jump_base_ = value; }
@@ -327,12 +317,12 @@
enum {
kApiInterrupt = 0x1, // An interrupt from Dart_InterruptIsolate.
kMessageInterrupt = 0x2, // An interrupt to process an out of band message.
- kStoreBufferInterrupt = 0x4, // An interrupt to process the store buffer.
+ kVMInterrupt = 0x4, // Internal VM checks: safepoints, store buffers, etc.
kInterruptsMask =
kApiInterrupt |
kMessageInterrupt |
- kStoreBufferInterrupt,
+ kVMInterrupt,
};
void ScheduleInterrupts(uword interrupt_bits);
@@ -696,6 +686,11 @@
RawUserTag* default_tag() const { return default_tag_; }
void set_default_tag(const UserTag& tag);
+ RawGrowableObjectArray* collected_closures() const {
+ return collected_closures_;
+ }
+ void set_collected_closures(const GrowableObjectArray& value);
+
Metric* metrics_list_head() {
return metrics_list_head_;
}
@@ -710,6 +705,11 @@
void set_deoptimized_code_array(const GrowableObjectArray& value);
void TrackDeoptimizedCode(const Code& code);
+ bool compilation_allowed() const { return compilation_allowed_; }
+ void set_compilation_allowed(bool allowed) {
+ compilation_allowed_ = allowed;
+ }
+
#if defined(DEBUG)
#define REUSABLE_HANDLE_SCOPE_ACCESSORS(object) \
void set_reusable_##object##_handle_scope_active(bool value) { \
@@ -748,8 +748,16 @@
}
private:
+ friend class Dart; // Init, InitOnce, Shutdown.
+
explicit Isolate(const Dart_IsolateFlags& api_flags);
+ static void InitOnce();
+ static Isolate* Init(const char* name_prefix,
+ const Dart_IsolateFlags& api_flags,
+ bool is_vm_isolate = false);
+ void Shutdown();
+
void BuildName(const char* name_prefix);
void PrintInvokedFunctions();
@@ -765,9 +773,17 @@
user_tag_ = tag;
}
- void set_mutator_thread(Thread* thread) {
+ void ClearMutatorThread() {
+ mutator_thread_ = NULL;
+ }
+ void MakeCurrentThreadMutator(Thread* thread) {
+ ASSERT(thread == Thread::Current());
+ DEBUG_ASSERT(IsIsolateOf(thread));
mutator_thread_ = thread;
}
+#if defined(DEBUG)
+ bool IsIsolateOf(Thread* thread);
+#endif // DEBUG
template<class T> T* AllocateReusableHandle();
@@ -792,7 +808,6 @@
Dart_EnvironmentCallback environment_callback_;
Dart_LibraryTagHandler library_tag_handler_;
ApiState* api_state_;
- StubCode* stub_code_;
Debugger* debugger_;
bool single_step_;
bool resume_request_;
@@ -850,12 +865,16 @@
RawGrowableObjectArray* tag_table_;
RawUserTag* current_tag_;
RawUserTag* default_tag_;
+
+ RawGrowableObjectArray* collected_closures_;
RawGrowableObjectArray* deoptimized_code_array_;
Metric* metrics_list_head_;
Counters counters_;
+ bool compilation_allowed_;
+
// TODO(23153): Move this out of Isolate/Thread.
CHA* cha_;
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 99c8354..f5f0506 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -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.
+#include "include/dart_api.h"
#include "platform/assert.h"
#include "vm/globals.h"
#include "vm/isolate.h"
@@ -10,14 +11,11 @@
namespace dart {
UNIT_TEST_CASE(IsolateCurrent) {
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT_EQ(isolate, Isolate::Current());
- isolate->Shutdown();
- EXPECT_EQ(reinterpret_cast<Isolate*>(NULL), Isolate::Current());
- delete isolate;
+ Dart_Isolate isolate = Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ EXPECT_EQ(isolate, Dart_CurrentIsolate());
+ Dart_ShutdownIsolate();
+ EXPECT_EQ(reinterpret_cast<Dart_Isolate>(NULL), Dart_CurrentIsolate());
}
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index 5b10ab0..6fc9e92 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -27,7 +27,7 @@
ObjectIdRing::kAllocateId),
id_zone_(&default_id_zone_),
reply_port_(ILLEGAL_PORT),
- seq_(""),
+ seq_(Instance::Handle(Instance::null())),
method_(""),
param_keys_(NULL),
param_values_(NULL),
@@ -41,12 +41,12 @@
void JSONStream::Setup(Zone* zone,
Dart_Port reply_port,
- const String& seq,
+ const Instance& seq,
const String& method,
const Array& param_keys,
const Array& param_values) {
set_reply_port(reply_port);
- seq_ = seq.ToCString();
+ seq_ ^= seq.raw();
method_ = method.ToCString();
String& string_iterator = String::Handle();
@@ -74,13 +74,13 @@
isolate_name, method_);
setup_time_micros_ = OS::GetCurrentTimeMicros();
}
- buffer_.Printf("{\"json-rpc\":\"2.0\", \"result\":");
+ buffer_.Printf("{\"jsonrpc\":\"2.0\", \"result\":");
}
void JSONStream::SetupError() {
buffer_.Clear();
- buffer_.Printf("{\"json-rpc\":\"2.0\", \"error\":");
+ buffer_.Printf("{\"jsonrpc\":\"2.0\", \"error\":");
}
@@ -162,8 +162,22 @@
if (FLAG_trace_service) {
process_delta_micros = OS::GetCurrentTimeMicros() - setup_time_micros_;
}
- // TODO(turnidge): Handle non-string sequence numbers.
- buffer_.Printf(", \"id\":\"%s\"}", seq());
+
+ if (seq_.IsString()) {
+ const String& str = String::Cast(seq_);
+ PrintProperty("id", str.ToCString());
+ } else if (seq_.IsInteger()) {
+ const Integer& integer = Integer::Cast(seq_);
+ PrintProperty64("id", integer.AsInt64Value());
+ } else if (seq_.IsDouble()) {
+ const Double& dbl = Double::Cast(seq_);
+ PrintProperty("id", dbl.value());
+ } else if (seq_.IsNull()) {
+ // JSON-RPC 2.0 says that a request with a null ID shouldn't get a reply.
+ return;
+ }
+ buffer_.AddChar('}');
+
const String& reply = String::Handle(String::New(ToCString()));
ASSERT(!reply.IsNull());
@@ -270,6 +284,11 @@
}
+void JSONStream::PrintValueTimeMillis(int64_t millis) {
+ PrintValue(static_cast<double>(millis));
+}
+
+
void JSONStream::PrintValue(double d) {
PrintCommaIfNeeded();
buffer_.Printf("%f", d);
@@ -422,6 +441,11 @@
}
+void JSONStream::PrintPropertyTimeMillis(const char* name, int64_t millis) {
+ PrintProperty(name, static_cast<double>(millis));
+}
+
+
void JSONStream::PrintProperty(const char* name, double d) {
PrintPropertyName(name);
PrintValue(d);
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 4ada4e7..e581560 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -57,7 +57,7 @@
void Setup(Zone* zone,
Dart_Port reply_port,
- const String& seq,
+ const Instance& seq,
const String& method,
const Array& param_keys,
const Array& param_values);
@@ -100,7 +100,6 @@
// otherwise.
bool ParamIs(const char* key, const char* value) const;
- const char* seq() const { return seq_; }
const char* method() const { return method_; }
const char** param_keys() const { return param_keys_; }
const char** param_values() const { return param_values_; }
@@ -117,6 +116,7 @@
void PrintValueBool(bool b);
void PrintValue(intptr_t i);
void PrintValue64(int64_t i);
+ void PrintValueTimeMillis(int64_t millis);
void PrintValue(double d);
void PrintValueBase64(const uint8_t* bytes, intptr_t length);
void PrintValue(const char* s);
@@ -136,6 +136,7 @@
void PrintPropertyBool(const char* name, bool b);
void PrintProperty(const char* name, intptr_t i);
void PrintProperty64(const char* name, int64_t i);
+ void PrintPropertyTimeMillis(const char* name, int64_t millis);
void PrintProperty(const char* name, double d);
void PrintPropertyBase64(const char* name,
const uint8_t* bytes,
@@ -169,7 +170,7 @@
RingServiceIdZone default_id_zone_;
ServiceIdZone* id_zone_;
Dart_Port reply_port_;
- const char* seq_;
+ Instance& seq_;
const char* method_;
const char** param_keys_;
const char** param_values_;
@@ -214,6 +215,9 @@
void AddProperty64(const char* name, int64_t i) const {
stream_->PrintProperty64(name, i);
}
+ void AddPropertyTimeMillis(const char* name, int64_t millis) const {
+ stream_->PrintPropertyTimeMillis(name, millis);
+ }
void AddProperty(const char* name, double d) const {
stream_->PrintProperty(name, d);
}
@@ -285,6 +289,9 @@
void AddValue(bool b) const { stream_->PrintValueBool(b); }
void AddValue(intptr_t i) const { stream_->PrintValue(i); }
void AddValue64(int64_t i) const { stream_->PrintValue64(i); }
+ void AddValueTimeMillis(int64_t millis) const {
+ stream_->PrintValueTimeMillis(millis);
+ }
void AddValue(double d) const { stream_->PrintValue(d); }
void AddValue(const char* s) const { stream_->PrintValue(s); }
void AddValue(const Object& obj, bool ref = true) const {
diff --git a/runtime/vm/log.cc b/runtime/vm/log.cc
index c62d8e5..5bb9842 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -118,7 +118,7 @@
LogBlock::LogBlock(Thread* thread, Log* log)
- : StackResource(thread->isolate()),
+ : StackResource(thread),
log_(log), cursor_(log->cursor()) {
CommonConstructor();
}
@@ -132,7 +132,7 @@
LogBlock::LogBlock(Thread* thread)
- : StackResource(thread->isolate()),
+ : StackResource(thread),
log_(thread->isolate()->Log()),
cursor_(thread->isolate()->Log()->cursor()) {
CommonConstructor();
diff --git a/runtime/vm/longjump.cc b/runtime/vm/longjump.cc
index 3ca64b3..66de5af 100644
--- a/runtime/vm/longjump.cc
+++ b/runtime/vm/longjump.cc
@@ -42,7 +42,8 @@
ASSERT(value != 0);
ASSERT(IsSafeToJump());
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
#if defined(DEBUG)
#define CHECK_REUSABLE_HANDLE(name) \
@@ -55,7 +56,7 @@
isolate->object_store()->set_sticky_error(error);
// Destruct all the active StackResource objects.
- StackResource::UnwindAbove(isolate, top_);
+ StackResource::UnwindAbove(thread, top_);
longjmp(environment_, value);
UNREACHABLE();
}
diff --git a/runtime/vm/metrics_test.cc b/runtime/vm/metrics_test.cc
index 364c946..9082739 100644
--- a/runtime/vm/metrics_test.cc
+++ b/runtime/vm/metrics_test.cc
@@ -14,20 +14,20 @@
namespace dart {
UNIT_TEST_CASE(Metric_Simple) {
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT_EQ(isolate, Isolate::Current());
- Metric metric;
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ {
+ Metric metric;
- // Initialize metric.
- metric.Init(Isolate::Current(), "a.b.c", "foobar", Metric::kCounter);
- EXPECT_EQ(0, metric.value());
- metric.increment();
- EXPECT_EQ(1, metric.value());
- metric.set_value(44);
- EXPECT_EQ(44, metric.value());
+ // Initialize metric.
+ metric.Init(Isolate::Current(), "a.b.c", "foobar", Metric::kCounter);
+ EXPECT_EQ(0, metric.value());
+ metric.increment();
+ EXPECT_EQ(1, metric.value());
+ metric.set_value(44);
+ EXPECT_EQ(44, metric.value());
+ }
+ Dart_ShutdownIsolate();
}
class MyMetric : public Metric {
@@ -43,27 +43,30 @@
};
UNIT_TEST_CASE(Metric_OnDemand) {
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT_EQ(isolate, Isolate::Current());
- MyMetric metric;
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ MyMetric metric;
- metric.Init(Isolate::Current(), "a.b.c", "foobar", Metric::kByte);
- // value is still the default value.
- EXPECT_EQ(0, metric.value());
- // Call LeakyValue to confirm that Value returns constant 99.
- EXPECT_EQ(99, metric.LeakyValue());
+ metric.Init(Isolate::Current(), "a.b.c", "foobar", Metric::kByte);
+ // value is still the default value.
+ EXPECT_EQ(0, metric.value());
+ // Call LeakyValue to confirm that Value returns constant 99.
+ EXPECT_EQ(99, metric.LeakyValue());
- // Serialize to JSON.
- JSONStream js;
- metric.PrintJSON(&js);
- const char* json = js.ToCString();
- EXPECT_STREQ("{\"type\":\"Counter\",\"name\":\"a.b.c\",\"description\":"
- "\"foobar\",\"unit\":\"byte\","
- "\"fixedId\":true,\"id\":\"metrics\\/native\\/a.b.c\""
- ",\"value\":99.000000}", json);
+ // Serialize to JSON.
+ JSONStream js;
+ metric.PrintJSON(&js);
+ const char* json = js.ToCString();
+ EXPECT_STREQ("{\"type\":\"Counter\",\"name\":\"a.b.c\",\"description\":"
+ "\"foobar\",\"unit\":\"byte\","
+ "\"fixedId\":true,\"id\":\"metrics\\/native\\/a.b.c\""
+ ",\"value\":99.000000}", json);
+ }
+ Dart_ShutdownIsolate();
}
} // namespace dart
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index a3cd5c1..a668897 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -11,6 +11,7 @@
#include "vm/message.h"
#include "vm/native_message_handler.h"
#include "vm/port.h"
+#include "vm/precompiler.h"
namespace dart {
@@ -79,6 +80,16 @@
}
}
+static void Precompile(Isolate* isolate, Dart_Handle* result) {
+ ASSERT(isolate != NULL);
+ const Error& error = Error::Handle(isolate, Precompiler::CompileAll());
+ if (error.IsNull()) {
+ *result = Api::Success();
+ } else {
+ *result = Api::NewHandle(isolate, error.raw());
+ }
+}
+
DART_EXPORT Dart_Handle Dart_CompileAll() {
Isolate* isolate = Isolate::Current();
@@ -92,4 +103,17 @@
return result;
}
+
+DART_EXPORT Dart_Handle Dart_Precompile() {
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ Dart_Handle result = Api::CheckAndFinalizePendingClasses(isolate);
+ if (::Dart_IsError(result)) {
+ return result;
+ }
+ CHECK_CALLBACK_STATE(isolate);
+ Precompile(isolate, &result);
+ return result;
+}
+
} // namespace dart
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 8f64388..3fb2f74 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -37,8 +37,8 @@
#define CHECK_STACK_ALIGNMENT { }
#else
#define CHECK_STACK_ALIGNMENT { \
- uword (*func)() = \
- reinterpret_cast<uword (*)()>(StubCode::GetStackPointerEntryPoint()); \
+ uword (*func)() = reinterpret_cast<uword (*)()>( \
+ StubCode::GetStackPointer_entry()->EntryPoint()); \
uword current_sp = func(); \
ASSERT(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment())); \
}
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index 39d9dcc..0180c09 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -88,7 +88,8 @@
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
/* Tell MemorySanitizer 'arguments' is initialized by generated code. */
MSAN_UNPOISON(arguments, sizeof(*arguments));
- Isolate* isolate = arguments->thread()->isolate();
+ Thread* thread = arguments->thread();
+ Isolate* isolate = thread->isolate();
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
@@ -97,12 +98,12 @@
TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func));
if (scope == NULL) {
scope = new ApiLocalScope(current_top_scope,
- isolate->top_exit_frame_info());
+ thread->top_exit_frame_info());
ASSERT(scope != NULL);
} else {
- scope->Reinit(isolate,
+ scope->Reinit(thread,
current_top_scope,
- isolate->top_exit_frame_info());
+ thread->top_exit_frame_info());
state->set_reusable_scope(NULL);
}
state->set_top_scope(scope); // New scope is now the top scope.
@@ -112,7 +113,7 @@
ASSERT(current_top_scope == scope->previous());
state->set_top_scope(current_top_scope); // Reset top scope to previous.
if (state->reusable_scope() == NULL) {
- scope->Reset(isolate); // Reset the old scope which we just exited.
+ scope->Reset(thread); // Reset the old scope which we just exited.
state->set_reusable_scope(scope);
} else {
ASSERT(state->reusable_scope() != scope);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f674cd4..83e45e9 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -635,7 +635,7 @@
// Allocate and initialize the empty_array instance.
{
uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld);
- InitializeObject(address, kArrayCid, Array::InstanceSize(0));
+ InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0));
Array::initializeHandle(
empty_array_,
reinterpret_cast<RawArray*>(address + kHeapObjectTag));
@@ -646,7 +646,7 @@
// Allocate and initialize the zero_array instance.
{
uword address = heap->Allocate(Array::InstanceSize(1), Heap::kOld);
- InitializeObject(address, kArrayCid, Array::InstanceSize(1));
+ InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1));
Array::initializeHandle(
zero_array_,
reinterpret_cast<RawArray*>(address + kHeapObjectTag));
@@ -899,7 +899,7 @@
void Object::MakeUnusedSpaceTraversable(const Object& obj,
intptr_t original_size,
intptr_t used_size) {
- ASSERT(Isolate::Current()->no_safepoint_scope_depth() > 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() > 0);
ASSERT(!obj.IsNull());
ASSERT(original_size >= used_size);
if (original_size > used_size) {
@@ -3475,6 +3475,11 @@
}
+void Class::set_is_allocated() const {
+ set_state_bits(IsAllocatedBit::update(true, raw_ptr()->state_bits_));
+}
+
+
void Class::set_is_finalized() const {
ASSERT(!is_finalized());
set_state_bits(ClassFinalizedBits::update(RawClass::kFinalized,
@@ -5177,18 +5182,16 @@
bool Function::HasCode() const {
ASSERT(raw_ptr()->instructions_ != Instructions::null());
- StubCode* stub_code = Isolate::Current()->stub_code();
return raw_ptr()->instructions_ !=
- stub_code->LazyCompile_entry()->code()->ptr()->instructions_;
+ StubCode::LazyCompile_entry()->code()->ptr()->instructions_;
}
void Function::ClearCode() const {
ASSERT(ic_data_array() == Array::null());
StorePointer(&raw_ptr()->unoptimized_code_, Code::null());
- StubCode* stub_code = Isolate::Current()->stub_code();
StorePointer(&raw_ptr()->instructions_,
- Code::Handle(stub_code->LazyCompile_entry()->code()).instructions());
+ Code::Handle(StubCode::LazyCompile_entry()->code()).instructions());
}
@@ -6198,6 +6201,12 @@
}
+bool Function::IsConstructorClosureFunction() const {
+ return IsClosureFunction() &&
+ String::Handle(name()).StartsWith(Symbols::ConstructorClosurePrefix());
+}
+
+
RawFunction* Function::New() {
ASSERT(Object::function_class() != Class::null());
RawObject* raw = Object::Allocate(Function::kClassId,
@@ -6251,8 +6260,7 @@
result.set_is_inlinable(true);
result.set_allows_hoisting_check_class(true);
result.set_allows_bounds_check_generalization(true);
- StubCode* stub_code = Isolate::Current()->stub_code();
- result.SetInstructions(Code::Handle(stub_code->LazyCompile_entry()->code()));
+ result.SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
if (kind == RawFunction::kClosureFunction) {
const ClosureData& data = ClosureData::Handle(ClosureData::New());
result.set_data(data);
@@ -6506,8 +6514,8 @@
if (implicit_static_closure() == Instance::null()) {
Isolate* isolate = Isolate::Current();
ObjectStore* object_store = isolate->object_store();
- const Context& context = Context::Handle(isolate,
- object_store->empty_context());
+ const Context& context =
+ Context::Handle(isolate, object_store->empty_context());
Instance& closure =
Instance::Handle(isolate, Closure::New(*this, context, Heap::kOld));
const char* error_str = NULL;
@@ -6846,6 +6854,7 @@
return raw_ptr()->ic_data_array_;
}
+
void Function::ClearICDataArray() const {
set_ic_data_array(Array::null_array());
}
@@ -7223,6 +7232,7 @@
result.set_owner(owner);
result.set_token_pos(token_pos);
result.set_has_initializer(false);
+ result.set_initializer(Function::Handle());
result.set_is_unboxing_candidate(true);
result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
result.set_is_nullable(FLAG_use_field_guards ? false : true);
@@ -7386,6 +7396,73 @@
}
}
+// Build a closure object that gets (or sets) the contents of a static
+// field f and cache the closure in a newly created static field
+// named #f (or #f= in case of a setter).
+RawInstance* Field::AccessorClosure(bool make_setter) const {
+ ASSERT(is_static());
+ const Class& field_owner = Class::Handle(owner());
+
+ String& closure_name = String::Handle(this->name());
+ closure_name = Symbols::FromConcat(Symbols::HashMark(), closure_name);
+ if (make_setter) {
+ closure_name = Symbols::FromConcat(Symbols::HashMark(), closure_name);
+ }
+
+ Field& closure_field = Field::Handle();
+ closure_field = field_owner.LookupStaticField(closure_name);
+ if (!closure_field.IsNull()) {
+ ASSERT(closure_field.is_static());
+ const Instance& closure = Instance::Handle(closure_field.value());
+ ASSERT(!closure.IsNull());
+ ASSERT(closure.IsClosure());
+ return closure.raw();
+ }
+
+ // This is the first time a closure for this field is requested.
+ // Create the closure and a new static field in which it is stored.
+ const char* field_name = String::Handle(name()).ToCString();
+ String& expr_src = String::Handle();
+ if (make_setter) {
+ expr_src =
+ String::NewFormatted("(%s_) { return %s = %s_; }",
+ field_name, field_name, field_name);
+ } else {
+ expr_src = String::NewFormatted("() { return %s; }", field_name);
+ }
+ Object& result =
+ Object::Handle(field_owner.Evaluate(expr_src,
+ Object::empty_array(),
+ Object::empty_array()));
+ ASSERT(result.IsInstance());
+ // The caller may expect the closure to be allocated in old space. Copy
+ // the result here, since Object::Clone() is a private method.
+ result = Object::Clone(result, Heap::kOld);
+
+ closure_field = Field::New(closure_name,
+ true, // is_static
+ true, // is_final
+ true, // is_const
+ true, // is_synthetic
+ field_owner,
+ this->token_pos());
+ closure_field.set_value(Instance::Cast(result));
+ closure_field.set_type(Type::Handle(Type::DynamicType()));
+ field_owner.AddField(closure_field);
+
+ return Instance::RawCast(result.raw());
+}
+
+
+RawInstance* Field::GetterClosure() const {
+ return AccessorClosure(false);
+}
+
+
+RawInstance* Field::SetterClosure() const {
+ return AccessorClosure(true);
+}
+
RawArray* Field::dependent_code() const {
return raw_ptr()->dependent_code_;
@@ -7452,6 +7529,11 @@
}
+void Field::set_initializer(const Function& initializer) const {
+ StorePointer(&raw_ptr()->initializer_, initializer.raw());
+}
+
+
void Field::EvaluateInitializer() const {
ASSERT(is_static());
if (value() == Object::sentinel().raw()) {
@@ -7632,6 +7714,10 @@
void Field::RecordStore(const Object& value) const {
+ if (!FLAG_use_field_guards) {
+ return;
+ }
+
if (FLAG_trace_field_guards) {
OS::Print("Store %s %s <- %s\n",
ToCString(),
@@ -10831,11 +10917,6 @@
}
-void ObjectPool::SetInfoAt(intptr_t index, EntryType info) const {
- const TypedData& array = TypedData::Handle(info_array());
- array.SetInt8(index, static_cast<int8_t>(info));
-}
-
const char* ObjectPool::ToCString() const {
return "ObjectPool";
}
@@ -12746,6 +12827,29 @@
}
+RawArray* Code::GetInlinedCallerIdMap() const {
+ const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
+ if (metadata.IsNull()) {
+ return metadata.raw();
+ }
+ return reinterpret_cast<RawArray*>(
+ metadata.At(RawCode::kInlinedCallerIdMapIndex));
+}
+
+
+void Code::SetInlinedCallerIdMap(const Array& value) const {
+ if (raw_ptr()->inlined_metadata_ == Array::null()) {
+ StorePointer(&raw_ptr()->inlined_metadata_,
+ Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
+ }
+ const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
+ ASSERT(!metadata.IsNull());
+ ASSERT(metadata.IsOld());
+ ASSERT(value.IsOld());
+ metadata.SetAt(RawCode::kInlinedCallerIdMapIndex, value);
+}
+
+
RawCode* Code::New(intptr_t pointer_offsets_length) {
if (pointer_offsets_length < 0 || pointer_offsets_length > kMaxElements) {
// This should be caught before we reach here.
@@ -12776,6 +12880,11 @@
RawCode* Code::FinalizeCode(const char* name,
Assembler* assembler,
bool optimized) {
+ Isolate* isolate = Isolate::Current();
+ if (!isolate->compilation_allowed()) {
+ FATAL1("Precompilation missed code %s\n", name);
+ }
+
ASSERT(assembler != NULL);
const ObjectPool& object_pool =
ObjectPool::Handle(assembler->object_pool_wrapper().MakeObjectPool());
@@ -12787,8 +12896,8 @@
Code& code = Code::ZoneHandle(Code::New(pointer_offset_count));
Instructions& instrs =
Instructions::ZoneHandle(Instructions::New(assembler->CodeSize()));
- INC_STAT(Isolate::Current(), total_instr_size, assembler->CodeSize());
- INC_STAT(Isolate::Current(), total_code_size, assembler->CodeSize());
+ INC_STAT(isolate, total_instr_size, assembler->CodeSize());
+ INC_STAT(isolate, total_code_size, assembler->CodeSize());
// Copy the instructions into the instruction area and apply all fixups.
// Embedded pointers are still in handles at this point.
@@ -12828,7 +12937,7 @@
code.set_is_alive(true);
// Set object pool in Instructions object.
- INC_STAT(Isolate::Current(),
+ INC_STAT(isolate,
total_code_size, object_pool.Length() * sizeof(uintptr_t));
instrs.set_object_pool(object_pool.raw());
@@ -12849,7 +12958,7 @@
// pushed onto the stack.
code.SetPrologueOffset(assembler->CodeSize());
}
- INC_STAT(Isolate::Current(),
+ INC_STAT(isolate,
total_code_size, code.comments().comments_.Length());
return code.raw();
}
@@ -13114,8 +13223,7 @@
temp_smi ^= intervals.At(i + Code::kInlIntInliningId);
intptr_t inlining_id = temp_smi.Value();
ASSERT(inlining_id >= 0);
- temp_smi ^= intervals.At(i + Code::kInlIntCallerId);
- intptr_t caller_id = temp_smi.Value();
+ intptr_t caller_id = GetCallerId(inlining_id);
while (inlining_id >= 0) {
inline_interval.AddValue(inlining_id);
inlining_id = caller_id;
@@ -13171,19 +13279,16 @@
intptr_t Code::GetCallerId(intptr_t inlined_id) const {
- if (inlined_id < 0) return -1;
- const Array& intervals = Array::Handle(GetInlinedIntervals());
- if (intervals.IsNull() || (intervals.Length() == 0)) return -1;
- Smi& temp_smi = Smi::Handle();
- for (intptr_t i = 0; i < intervals.Length() - Code::kInlIntNumEntries;
- i += Code::kInlIntNumEntries) {
- temp_smi ^= intervals.At(i + Code::kInlIntInliningId);
- if (temp_smi.Value() == inlined_id) {
- temp_smi ^= intervals.At(i + Code::kInlIntCallerId);
- return temp_smi.Value();
- }
+ if (inlined_id < 0) {
+ return -1;
}
- return -1;
+ const Array& map = Array::Handle(GetInlinedCallerIdMap());
+ if (map.IsNull() || (map.Length() == 0)) {
+ return -1;
+ }
+ Smi& smi = Smi::Handle();
+ smi ^= map.At(inlined_id);
+ return smi.Value();
}
@@ -13218,8 +13323,7 @@
temp_smi ^= intervals.At(found_interval_ix + Code::kInlIntInliningId);
intptr_t inlining_id = temp_smi.Value();
ASSERT(inlining_id >= 0);
- temp_smi ^= intervals.At(found_interval_ix + Code::kInlIntCallerId);
- intptr_t caller_id = temp_smi.Value();
+ intptr_t caller_id = GetCallerId(inlining_id);
while (inlining_id >= 0) {
Function& function = Function::ZoneHandle();
function ^= id_map.At(inlining_id);
@@ -13231,30 +13335,52 @@
void Code::DumpInlinedIntervals() const {
- OS::Print("Inlined intervals:\n");
+ LogBlock lb(Isolate::Current());
+ ISL_Print("Inlined intervals:\n");
const Array& intervals = Array::Handle(GetInlinedIntervals());
if (intervals.IsNull() || (intervals.Length() == 0)) return;
Smi& start = Smi::Handle();
Smi& inlining_id = Smi::Handle();
- Smi& caller_id = Smi::Handle();
+ GrowableArray<Function*> inlined_functions;
+ const Function& inliner = Function::Handle(function());
for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) {
start ^= intervals.At(i + Code::kInlIntStart);
ASSERT(!start.IsNull());
if (start.IsNull()) continue;
inlining_id ^= intervals.At(i + Code::kInlIntInliningId);
- caller_id ^= intervals.At(i + Code::kInlIntCallerId);
- OS::Print(" %" Px " id: %" Pd " caller-id: %" Pd " \n",
- start.Value(), inlining_id.Value(), caller_id.Value());
+ ISL_Print(" %" Px " iid: %" Pd " ; ", start.Value(), inlining_id.Value());
+ inlined_functions.Clear();
+
+ ISL_Print("inlined: ");
+ GetInlinedFunctionsAt(start.Value(), &inlined_functions);
+
+ for (intptr_t j = 0; j < inlined_functions.length(); j++) {
+ const char* name = inlined_functions[j]->ToQualifiedCString();
+ ISL_Print(" %s <-", name);
+ }
+ if (inlined_functions[inlined_functions.length() - 1]->raw() !=
+ inliner.raw()) {
+ ISL_Print(" (ERROR, missing inliner)\n");
+ } else {
+ ISL_Print("\n");
+ }
}
- OS::Print("Inlined ids:\n");
+ ISL_Print("Inlined ids:\n");
const Array& id_map = Array::Handle(GetInlinedIdToFunction());
Function& function = Function::Handle();
for (intptr_t i = 0; i < id_map.Length(); i++) {
function ^= id_map.At(i);
if (!function.IsNull()) {
- OS::Print(" %" Pd ": %s\n", i, function.ToQualifiedCString());
+ ISL_Print(" %" Pd ": %s\n", i, function.ToQualifiedCString());
}
}
+ ISL_Print("Caller Inlining Ids:\n");
+ const Array& caller_map = Array::Handle(GetInlinedCallerIdMap());
+ Smi& smi = Smi::Handle();
+ for (intptr_t i = 0; i < caller_map.Length(); i++) {
+ smi ^= caller_map.At(i);
+ ISL_Print(" iid: %" Pd " caller iid: %" Pd "\n", i, smi.Value());
+ }
}
@@ -14301,7 +14427,7 @@
intptr_t* Instance::NativeFieldsDataAddr() const {
- ASSERT(Isolate::Current()->no_safepoint_scope_depth() > 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() > 0);
RawTypedData* native_fields =
reinterpret_cast<RawTypedData*>(*NativeFieldsAddr());
if (native_fields == TypedData::null()) {
@@ -14450,7 +14576,7 @@
return "unknown_constant";
} else if (raw() == Object::non_constant().raw()) {
return "non_constant";
- } else if (Isolate::Current()->no_safepoint_scope_depth() > 0) {
+ } else if (Thread::Current()->no_safepoint_scope_depth() > 0) {
// Can occur when running disassembler.
return "Instance";
} else {
@@ -15529,7 +15655,9 @@
if ((index == 0) && cls.IsCanonicalSignatureClass()) {
// Verify that the first canonical type is the signature type by checking
// that the type argument vector of the canonical type ends with the
- // uninstantiated type parameters of the signature class.
+ // uninstantiated type parameters of the signature class. Note that these
+ // type parameters may be bounded if the super class of the owner class
+ // declares bounds.
// The signature type is finalized during class finalization, before the
// optimizer may canonicalize instantiated function types of the same
// signature class.
@@ -15540,10 +15668,13 @@
TypeArguments::Handle(isolate, cls.type_parameters());
const intptr_t num_type_params = cls.NumTypeParameters();
const intptr_t num_type_args = cls.NumTypeArguments();
- TypeParameter& type_arg = TypeParameter::Handle(isolate);
+ AbstractType& type_arg = AbstractType::Handle(isolate);
TypeParameter& type_param = TypeParameter::Handle(isolate);
for (intptr_t i = 0; i < num_type_params; i++) {
- type_arg ^= type_args.TypeAt(num_type_args - num_type_params + i);
+ type_arg = type_args.TypeAt(num_type_args - num_type_params + i);
+ while (type_arg.IsBoundedType()) {
+ type_arg = BoundedType::Cast(type_arg).type();
+ }
type_param ^= type_params.TypeAt(i);
ASSERT(type_arg.Equals(type_param));
}
@@ -19669,6 +19800,7 @@
void Array::MakeImmutable() const {
+ if (IsImmutable()) return;
NoSafepointScope no_safepoint;
uword tags = raw_ptr()->tags_;
uword old_tags;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index b259aac..5bfc041 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -274,6 +274,10 @@
ASSERT(!IsNull());
raw()->SetCanonical();
}
+ void ClearCanonical() const {
+ ASSERT(!IsNull());
+ raw()->ClearCanonical();
+ }
intptr_t GetClassId() const {
return !raw()->IsHeapObject() ?
static_cast<intptr_t>(kSmiCid) : raw()->GetClassId();
@@ -684,7 +688,7 @@
ASSERT(Contains(reinterpret_cast<uword>(addr) - 1) &&
Contains(reinterpret_cast<uword>(addr) - kWordSize));
// At least check that there is a NoSafepointScope and hope it's big enough.
- ASSERT(Isolate::Current()->no_safepoint_scope_depth() > 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() > 0);
return const_cast<FieldType*>(addr);
}
@@ -1278,6 +1282,11 @@
}
void set_is_cycle_free() const;
+ bool is_allocated() const {
+ return IsAllocatedBit::decode(raw_ptr()->state_bits_);
+ }
+ void set_is_allocated() const;
+
uint16_t num_native_fields() const {
return raw_ptr()->num_native_fields_;
}
@@ -1395,6 +1404,7 @@
kCycleFreeBit = 12,
kEnumBit = 13,
kTraceAllocationBit = 14,
+ kIsAllocatedBit = 15,
};
class ConstBit : public BitField<bool, kConstBit, 1> {};
class ImplementedBit : public BitField<bool, kImplementedBit, 1> {};
@@ -1412,6 +1422,7 @@
class CycleFreeBit : public BitField<bool, kCycleFreeBit, 1> {};
class EnumBit : public BitField<bool, kEnumBit, 1> {};
class TraceAllocationBit : public BitField<bool, kTraceAllocationBit, 1> {};
+ class IsAllocatedBit : public BitField<bool, kIsAllocatedBit, 1> {};
void set_name(const String& value) const;
void set_pretty_name(const String& value) const;
@@ -2481,6 +2492,8 @@
return !is_static() && IsImplicitClosureFunction();
}
+ bool IsConstructorClosureFunction() const;
+
// Returns true if this function represents a local function.
bool IsLocalFunction() const {
return parent_function() != Function::null();
@@ -2944,6 +2957,17 @@
void EvaluateInitializer() const;
+ RawFunction* initializer() const {
+ return raw_ptr()->initializer_;
+ }
+ void set_initializer(const Function& initializer) const;
+
+ // For static fields only. Constructs a closure that gets/sets the
+ // field value.
+ RawInstance* GetterClosure() const;
+ RawInstance* SetterClosure() const;
+ RawInstance* AccessorClosure(bool make_setter) const;
+
// Constructs getter and setter names for fields and vice versa.
static RawString* GetterName(const String& field_name);
static RawString* GetterSymbol(const String& field_name);
@@ -3563,7 +3587,6 @@
}
EntryType InfoAt(intptr_t index) const;
- void SetInfoAt(intptr_t index, EntryType info) const;
RawObject* ObjectAt(intptr_t index) const {
ASSERT(InfoAt(index) == kTaggedObject);
@@ -4136,8 +4159,7 @@
enum InlinedIntervalEntries {
kInlIntStart = 0,
kInlIntInliningId = 1,
- kInlIntCallerId = 2,
- kInlIntNumEntries = 3,
+ kInlIntNumEntries = 2,
};
RawArray* GetInlinedIntervals() const;
@@ -4146,6 +4168,9 @@
RawArray* GetInlinedIdToFunction() const;
void SetInlinedIdToFunction(const Array& value) const;
+ RawArray* GetInlinedCallerIdMap() const;
+ void SetInlinedCallerIdMap(const Array& value) const;
+
void GetInlinedFunctionsAt(
intptr_t offset, GrowableArray<Function*>* fs) const;
diff --git a/runtime/vm/object_arm64_test.cc b/runtime/vm/object_arm64_test.cc
index 44dec3b..9383cc2 100644
--- a/runtime/vm/object_arm64_test.cc
+++ b/runtime/vm/object_arm64_test.cc
@@ -37,8 +37,9 @@
String::ZoneHandle(String::New(str, Heap::kOld));
__ mov(SP, CSP);
__ TagAndPushPP(); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadObject(R0, string_object, PP);
+ __ LoadPoolPointer();
+ __ LoadObject(R0, string_object);
+ __ set_constant_pool_allowed(false);
__ PopAndUntagPP(); // Restore caller's pool pointer.
__ ret();
}
@@ -49,7 +50,7 @@
void GenerateEmbedSmiInCode(Assembler* assembler, intptr_t value) {
const Smi& smi_object = Smi::ZoneHandle(Smi::New(value));
const int64_t val = reinterpret_cast<int64_t>(smi_object.raw());
- __ LoadImmediate(R0, val, kNoRegister);
+ __ LoadImmediate(R0, val);
__ ret();
}
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 2e30f25..ad6f861 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -256,14 +256,30 @@
// We cannot use a GrowableObjectArray, since we must not trigger GC.
RetainingPathVisitor(RawObject* obj, const Array& path)
: obj_(obj), path_(path), length_(0) {
- ASSERT(Isolate::Current()->no_safepoint_scope_depth() != 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
}
intptr_t length() const { return length_; }
+ bool ShouldSkip(RawObject* obj) {
+ // A retaining path through ICData is never the only retaining path,
+ // and it is less informative than its alternatives.
+ intptr_t cid = obj->GetClassId();
+ switch (cid) {
+ case kICDataCid:
+ return true;
+ default:
+ return false;
+ }
+ }
+
virtual Direction VisitObject(ObjectGraph::StackIterator* it) {
if (it->Get() != obj_) {
- return kProceed;
+ if (ShouldSkip(it->Get())) {
+ return kBacktrack;
+ } else {
+ return kProceed;
+ }
} else {
HANDLESCOPE(Isolate::Current());
Object& current = Object::Handle();
@@ -313,7 +329,7 @@
Object* scratch)
: ObjectVisitor(isolate), ObjectPointerVisitor(isolate), source_(NULL),
target_(target), references_(references), scratch_(scratch), length_(0) {
- ASSERT(Isolate::Current()->no_safepoint_scope_depth() != 0);
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
}
intptr_t length() const { return length_; }
diff --git a/runtime/vm/object_x64_test.cc b/runtime/vm/object_x64_test.cc
index b8914e0..639d8d0 100644
--- a/runtime/vm/object_x64_test.cc
+++ b/runtime/vm/object_x64_test.cc
@@ -35,8 +35,8 @@
const String& string_object =
String::ZoneHandle(String::New(str, Heap::kOld));
__ pushq(PP); // Save caller's pool pointer and load a new one here.
- __ LoadPoolPointer(PP);
- __ LoadObject(RAX, string_object, PP);
+ __ LoadPoolPointer();
+ __ LoadObject(RAX, string_object);
__ popq(PP); // Restore caller's pool pointer.
__ ret();
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 80e45ed..0179633 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -48,6 +48,7 @@
DECLARE_FLAG(bool, lazy_dispatchers);
DECLARE_FLAG(bool, load_deferred_eagerly);
+DECLARE_FLAG(bool, profile_vm);
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
@@ -318,6 +319,7 @@
// For parsing a compilation unit.
Parser::Parser(const Script& script, const Library& library, intptr_t token_pos)
: isolate_(Thread::Current()->isolate()),
+ thread_(Thread::Current()),
script_(Script::Handle(zone(), script.raw())),
tokens_iterator_(TokenStream::Handle(zone(), script.tokens()),
token_pos),
@@ -347,6 +349,7 @@
ParsedFunction* parsed_function,
intptr_t token_position)
: isolate_(Thread::Current()->isolate()),
+ thread_(Thread::Current()),
script_(Script::Handle(zone(), script.raw())),
tokens_iterator_(TokenStream::Handle(zone(), script.tokens()),
token_position),
@@ -554,6 +557,13 @@
AddFinalParameter(token_pos, &Symbols::This(), receiver_type);
}
+ void EraseParameterTypes() {
+ const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
+ const int num_parameters = parameters->length();
+ for (int i = 0; i < num_parameters; i++) {
+ (*parameters)[i].type = &dynamic_type;
+ }
+ }
// Make the parameter variables visible/invisible.
// Field initializer parameters are always invisible.
@@ -829,11 +839,46 @@
}
+bool Parser::ParseFormalParameters(const Function& func, ParamList* params) {
+ ASSERT(!func.IsNull());
+ // This is currently only used for constructors. To handle all kinds
+ // of functions, special cases for getters and possibly other kinds
+ // need to be added.
+ ASSERT(func.kind() == RawFunction::kConstructor);
+ ASSERT(!func.IsRedirectingFactory());
+ // Implicit constructors have no source, no user-defined formal parameters.
+ if (func.IsImplicitConstructor()) {
+ return true;
+ }
+ LongJumpScope jump;
+ if (setjmp(*jump.Set()) == 0) {
+ const Script& script = Script::Handle(func.script());
+ const Class& owner = Class::Handle(func.Owner());
+ ASSERT(!owner.IsNull());
+ ParsedFunction* parsed_function =
+ new ParsedFunction(Thread::Current(), Function::ZoneHandle(func.raw()));
+ Parser parser(script, parsed_function, func.token_pos());
+ parser.SkipFunctionPreamble();
+ parser.ParseFormalParameterList(true, true, params);
+ return true;
+ } else {
+ Thread::Current()->isolate()->object_store()->clear_sticky_error();
+ params->Clear();
+ return false;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+
void Parser::ParseFunction(ParsedFunction* parsed_function) {
Isolate* isolate = parsed_function->isolate();
Zone* zone = parsed_function->zone();
CSTAT_TIMER_SCOPE(isolate, parser_timer);
INC_STAT(isolate, num_functions_compiled, 1);
+ VMTagScope tagScope(isolate, VMTag::kCompileParseFunctionTagId,
+ FLAG_profile_vm);
+
ASSERT(isolate->long_jump_base()->IsSafeToJump());
ASSERT(parsed_function != NULL);
const Function& func = parsed_function->function();
@@ -844,11 +889,15 @@
switch (func.kind()) {
case RawFunction::kClosureFunction:
if (func.IsImplicitClosureFunction()) {
- parser.SkipFunctionPreamble();
node_sequence =
parser.ParseImplicitClosure(func, &default_parameter_values);
break;
}
+ if (func.IsConstructorClosureFunction()) {
+ node_sequence =
+ parser.ParseConstructorClosure(func, &default_parameter_values);
+ break;
+ }
// Fall-through: Handle non-implicit closures.
case RawFunction::kRegularFunction:
case RawFunction::kGetterFunction:
@@ -1058,7 +1107,6 @@
ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) {
ASSERT(field.is_static());
- ASSERT(field.value() == Object::transition_sentinel().raw());
Thread* thread = Thread::Current();
// TODO(koda): Should there be a StackZone here?
Zone* zone = thread->zone();
@@ -1282,29 +1330,93 @@
}
+SequenceNode* Parser::ParseConstructorClosure(const Function& func,
+ Array* default_values) {
+ TRACE_PARSER("ParseConstructorClosure");
+ const intptr_t token_pos = func.token_pos();
+
+ Function& constructor = Function::ZoneHandle(Z);
+ TypeArguments& type_args = TypeArguments::ZoneHandle(Z);
+ ParseConstructorClosurization(&constructor, &type_args);
+ ASSERT(!constructor.IsNull());
+
+ ParamList params;
+ // The first parameter of the closure function is the implicit closure
+ // argument.
+ params.AddFinalParameter(token_pos,
+ &Symbols::ClosureParameter(),
+ &Type::ZoneHandle(Z, Type::DynamicType()));
+ bool params_ok = ParseFormalParameters(constructor, ¶ms);
+ USE(params_ok);
+ ASSERT(params_ok);
+ // Per language spec, the type of the closure parameters is dynamic.
+ // Replace the types parsed from the constructor.
+ params.EraseParameterTypes();
+
+ SetupDefaultsForOptionalParams(¶ms, default_values);
+ ASSERT(func.num_fixed_parameters() == params.num_fixed_parameters);
+ ASSERT(func.NumOptionalParameters() == params.num_optional_parameters);
+
+ OpenFunctionBlock(func);
+ LocalScope* scope = current_block_->scope;
+ AddFormalParamsToScope(¶ms, scope);
+
+ ArgumentListNode* ctor_args = new ArgumentListNode(token_pos);
+ // Skip implicit closure parameter at 0.
+ for (intptr_t i = 1; i < func.NumParameters(); i++) {
+ ctor_args->Add(new LoadLocalNode(token_pos, scope->VariableAt(i)));
+ }
+
+ if (func.HasOptionalNamedParameters()) {
+ const Array& arg_names =
+ Array::ZoneHandle(Array::New(func.NumOptionalParameters()));
+ for (intptr_t i = 0; i < arg_names.Length(); i++) {
+ intptr_t index = func.num_fixed_parameters() + i;
+ arg_names.SetAt(i, String::Handle(func.ParameterNameAt(index)));
+ }
+ ctor_args->set_names(arg_names);
+ }
+
+ AstNode* new_object =
+ CreateConstructorCallNode(token_pos, type_args, constructor, ctor_args);
+ ReturnNode* return_node = new ReturnNode(token_pos, new_object);
+ current_block_->statements->Add(return_node);
+ return CloseBlock();
+}
+
+
SequenceNode* Parser::ParseImplicitClosure(const Function& func,
Array* default_values) {
TRACE_PARSER("ParseImplicitClosure");
-
intptr_t token_pos = func.token_pos();
OpenFunctionBlock(func);
ParamList params;
-
params.AddFinalParameter(
token_pos,
&Symbols::ClosureParameter(),
&Type::ZoneHandle(Type::DynamicType()));
- const bool allow_explicit_default_values = true;
- ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
- SetupDefaultsForOptionalParams(¶ms, default_values);
-
- // Getters can't be closurized. If supported, they need special
- // handling of the parameters as in ParseFunc.
const Function& parent = Function::ZoneHandle(func.parent_function());
- ASSERT(!parent.IsGetterFunction());
+ if (parent.IsImplicitSetterFunction()) {
+ const intptr_t ident_pos = func.token_pos();
+ ASSERT(IsIdentifier());
+ const String& field_name = *CurrentLiteral();
+ const Class& field_class = Class::ZoneHandle(Z, parent.Owner());
+ const Field& field =
+ Field::ZoneHandle(Z, field_class.LookupInstanceField(field_name));
+ const AbstractType& field_type = AbstractType::ZoneHandle(Z, field.type());
+ params.AddFinalParameter(ident_pos,
+ &Symbols::Value(),
+ &field_type);
+ ASSERT(func.num_fixed_parameters() == 2); // closure, value.
+ } else if (!parent.IsGetterFunction() && !parent.IsImplicitGetterFunction()) {
+ const bool allow_explicit_default_values = true;
+ SkipFunctionPreamble();
+ ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
+ SetupDefaultsForOptionalParams(¶ms, default_values);
+ }
// Populate function scope with the formal parameters.
LocalScope* scope = current_block_->scope;
@@ -3429,8 +3541,9 @@
RawLibraryPrefix* Parser::ParsePrefix() {
ASSERT(IsIdentifier());
// A library prefix can never stand by itself. It must be followed by
- // a period.
- if (LookaheadToken(1) != Token::kPERIOD) {
+ // a period or a hash mark (for closurization).
+ Token::Kind next_token = LookaheadToken(1);
+ if ((next_token != Token::kPERIOD) && (next_token != Token::kHASH)) {
return LibraryPrefix::null();
}
const String& ident = *CurrentLiteral();
@@ -3457,10 +3570,8 @@
return LibraryPrefix::null();
}
- // We have a name that is not shadowed, followed by a period.
- // Consume the identifier and the period.
- ConsumeToken();
- ASSERT(CurrentToken() == Token::kPERIOD); // We checked above.
+ // We have a name that is not shadowed, followed by a period or #.
+ // Consume the identifier, let the caller consume the . or #.
ConsumeToken();
return prefix.raw();
}
@@ -5300,6 +5411,8 @@
}
SkipExpr();
field.set_value(field_value);
+ field.set_has_initializer(true);
+
if (!has_simple_literal) {
// Create a static final getter.
String& getter_name = String::Handle(Z, Field::GetterSymbol(var_name));
@@ -5815,7 +5928,7 @@
prefix.ToCString());
}
if (is_deferred_import) {
- ReportError(prefix_pos, "prefix of deferred import must be uniqe");
+ ReportError(prefix_pos, "prefix of deferred import must be unique");
}
library_prefix.AddImport(ns);
} else {
@@ -7472,10 +7585,10 @@
// Since the signature type is cached by the signature class, it may have
// been finalized already.
- Type& signature_type = Type::Handle(Z,
- signature_class.SignatureType());
- TypeArguments& signature_type_arguments = TypeArguments::Handle(Z,
- signature_type.arguments());
+ Type& signature_type =
+ Type::Handle(Z, signature_class.SignatureType());
+ TypeArguments& signature_type_arguments =
+ TypeArguments::Handle(Z, signature_type.arguments());
if (!signature_type.IsFinalized()) {
signature_type ^= ClassFinalizer::FinalizeType(
@@ -11316,13 +11429,156 @@
}
+// Closurization e#m of getter, setter, method or operator.
+AstNode* Parser::ParseClosurization(AstNode* primary) {
+ ExpectToken(Token::kHASH);
+ intptr_t property_pos = TokenPos();
+ bool is_setter_name = false;
+
+ String& extractor_name = String::ZoneHandle(Z);
+ if (IsIdentifier()) {
+ extractor_name = CurrentLiteral()->raw();
+ ConsumeToken();
+ if (CurrentToken() == Token::kASSIGN) {
+ ConsumeToken();
+ is_setter_name = true;
+ }
+ } else if (Token::CanBeOverloaded(CurrentToken())) {
+ extractor_name = String::New(Token::Str(CurrentToken()));
+ ConsumeToken();
+ } else {
+ ReportError("identifier or operator expected");
+ }
+
+ if (primary->IsPrimaryNode() && primary->AsPrimaryNode()->IsSuper()) {
+ // TODO(hausner): implement super#m
+ ReportError("closurization of super method not yet supported");
+ }
+
+ // Handle closurization of top-level names from library prefixes, P#m
+ if (primary->IsLiteralNode() &&
+ primary->AsLiteralNode()->literal().IsLibraryPrefix()) {
+ const LibraryPrefix& prefix =
+ LibraryPrefix::Cast(primary->AsLiteralNode()->literal());
+ Object& obj = Object::Handle(Z);
+ const bool is_private_name =
+ (extractor_name.CharAt(0) == Library::kPrivateIdentifierStart);
+ if (!is_private_name) {
+ // Private names are not exported by libraries. The name mangling
+ // of private names with a library-specific suffix usually ensures
+ // that _x in library A is not found when looked up from library B.
+ // In the pathological case where a library imports itself with
+ // a prefix, the name mangling does not help in hiding the private
+ // name, so we explicitly prevent lookup of private names here.
+ obj = prefix.LookupObject(extractor_name);
+ }
+ if (!prefix.is_loaded() && (parsed_function() != NULL)) {
+ // Remember that this function depends on an import prefix of an
+ // unloaded deferred library.
+ parsed_function()->AddDeferredPrefix(prefix);
+ }
+
+ if (obj.IsFunction()) {
+ const Function& func = Function::Cast(obj);
+ if (!func.IsSetterFunction() || is_setter_name) {
+ return CreateImplicitClosureNode(func, property_pos, NULL);
+ }
+ } else if (obj.IsField()) {
+ const Field& field = Field::Cast(obj);
+ if (is_setter_name && !field.is_final()) {
+ Instance& setter_closure = Instance::ZoneHandle(field.SetterClosure());
+ return new(Z) LiteralNode(property_pos, setter_closure);
+ }
+ if (!is_setter_name) {
+ Instance& getter_closure = Instance::ZoneHandle(field.GetterClosure());
+ return new(Z) LiteralNode(property_pos, getter_closure);
+ }
+ }
+ return ThrowNoSuchMethodError(property_pos,
+ current_class(),
+ extractor_name,
+ NULL, // No arguments.
+ InvocationMirror::kTopLevel,
+ is_setter_name
+ ? InvocationMirror::kSetter
+ : InvocationMirror::kMethod,
+ NULL); // No existing function.
+ }
+
+ // Handle closurization of static properties of classes, C#n.
+ if (primary->IsPrimaryNode() &&
+ primary->AsPrimaryNode()->primary().IsClass()) {
+ const Class& cls = Class::Cast(primary->AsPrimaryNode()->primary());
+ const Field& field =
+ Field::Handle(Z, cls.LookupStaticField(extractor_name));
+ if (!field.IsNull()) {
+ if (is_setter_name) {
+ extractor_name = Field::SetterName(extractor_name);
+ if (!field.is_final()) {
+ const Instance& setter_closure =
+ Instance::ZoneHandle(Z, field.SetterClosure());
+ ASSERT(setter_closure.IsClosure());
+ // Note: the created closure is cached after it's created
+ // once. If eager compilation is desired, the compiler can
+ // be invoked here. The same applies for getters below.
+ return new(Z) LiteralNode(property_pos, setter_closure);
+ }
+ } else {
+ const Instance& getter_closure =
+ Instance::ZoneHandle(Z, field.GetterClosure());
+ ASSERT(getter_closure.IsClosure());
+ return new(Z) LiteralNode(property_pos, getter_closure);
+ }
+ } else {
+ Function& func = Function::Handle(Z);
+ if (is_setter_name) {
+ extractor_name = Field::SetterName(extractor_name);
+ func = cls.LookupStaticFunction(extractor_name);
+ } else {
+ func = cls.LookupStaticFunction(extractor_name);
+ if (func.IsNull()) {
+ const String& getter_name =
+ String::Handle(Z, Field::GetterName(extractor_name));
+ func = cls.LookupStaticFunction(getter_name);
+ }
+ }
+ if (!func.IsNull()) {
+ return CreateImplicitClosureNode(func, property_pos, NULL);
+ }
+ }
+ return ThrowNoSuchMethodError(property_pos,
+ cls,
+ extractor_name,
+ NULL, // No arguments.
+ InvocationMirror::kStatic,
+ is_setter_name
+ ? InvocationMirror::kSetter
+ : InvocationMirror::kMethod,
+ NULL); // No existing function.
+ }
+
+ // Closurization of instance getter, setter, method or operator.
+ if (is_setter_name) {
+ extractor_name = String::Concat(Symbols::SetterPrefix(), extractor_name);
+ }
+ extractor_name = String::Concat(Symbols::HashMark(), extractor_name);
+ extractor_name = Symbols::New(extractor_name);
+ return new(Z) InstanceGetterNode(property_pos, primary, extractor_name);
+}
+
+
AstNode* Parser::ParsePostfixExpr() {
TRACE_PARSER("ParsePostfixExpr");
String* expr_ident =
Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
const intptr_t expr_pos = TokenPos();
AstNode* expr = ParsePrimary();
- expr = ParseSelectors(expr, false);
+ if (CurrentToken() == Token::kHASH) {
+ expr = LoadFieldIfUnresolved(expr);
+ expr = ParseClosurization(expr);
+ } else {
+ expr = ParseSelectors(expr, false);
+ }
if (IsIncrementOperator(CurrentToken())) {
TRACE_PARSER("IncrementOperator");
if (!IsLegalAssignableSyntax(expr, TokenPos())) {
@@ -12004,6 +12260,9 @@
SkipQualIdent();
} else {
*prefix = ParsePrefix();
+ if (!prefix->IsNull()) {
+ ExpectToken(Token::kPERIOD);
+ }
type_name = CurrentLiteral()->raw();
ConsumeToken();
@@ -12603,6 +12862,50 @@
}
+RawFunction* Parser::BuildConstructorClosureFunction(const Function& ctr,
+ intptr_t token_pos) {
+ ASSERT(ctr.kind() == RawFunction::kConstructor);
+ String& closure_name = String::Handle(Z, ctr.name());
+ closure_name = Symbols::FromConcat(Symbols::ConstructorClosurePrefix(),
+ closure_name);
+ ParamList params;
+ params.AddFinalParameter(token_pos,
+ &Symbols::ClosureParameter(),
+ &Type::ZoneHandle(Z, Type::DynamicType()));
+
+ ParseFormalParameters(ctr, ¶ms);
+ // Per language spec, the type of the closure parameters is dynamic.
+ // Replace the types parsed from the constructor.
+ params.EraseParameterTypes();
+
+ Function& closure = Function::Handle(Z);
+ closure = Function::NewClosureFunction(closure_name,
+ innermost_function(),
+ token_pos);
+ closure.set_is_generated_body(true);
+ closure.set_result_type(AbstractType::Handle(Type::DynamicType()));
+ AddFormalParamsToFunction(¶ms, closure);
+
+ // Create and set the signature class of the closure.
+ const String& sig = String::Handle(Z, closure.Signature());
+ Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
+ if (sig_cls.IsNull()) {
+ sig_cls = Class::NewSignatureClass(sig, closure, script_, token_pos);
+ library_.AddClass(sig_cls);
+ }
+ closure.set_signature_class(sig_cls);
+ const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
+ if (!sig_type.IsFinalized()) {
+ // Finalization would be premature when top-level parsing.
+ ASSERT(!is_top_level_);
+ ClassFinalizer::FinalizeType(sig_cls,
+ sig_type,
+ ClassFinalizer::kCanonicalize);
+ }
+ return closure.raw();
+}
+
+
static String& BuildConstructorName(const String& type_class_name,
const String* named_constructor) {
// By convention, the static function implementing a named constructor 'C'
@@ -12618,6 +12921,61 @@
}
+// Parse a primary expression of the form new T# or new T#m.
+// Current token position is after the keyword new. Extracts the
+// anonymous or named constructor and type arguments.
+// Note that type type T has already been parsed before
+// (by ParseNewOperator()) and is guaranteed to be well-formed,
+// and the constructor is known to exist.
+void Parser::ParseConstructorClosurization(Function* constructor,
+ TypeArguments* type_arguments) {
+ *constructor = Function::null();
+ *type_arguments = TypeArguments::null();
+ const Token::Kind la3 = LookaheadToken(3);
+ const bool consume_unresolved_prefix =
+ (la3 == Token::kLT) || (la3 == Token::kPERIOD) || (la3 == Token::kHASH);
+ LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z);
+ AbstractType& type = AbstractType::Handle(Z,
+ ParseType(ClassFinalizer::kCanonicalizeWellFormed,
+ true, // allow deferred type
+ consume_unresolved_prefix,
+ &prefix));
+ // A constructor tear-off closure can only have been created for a
+ // type that is loaded.
+ ASSERT(prefix.IsNull() || prefix.is_loaded());
+ ASSERT(!type.IsMalformed() && !type.IsTypeParameter());
+ ExpectToken(Token::kHASH);
+ String* named_constructor = NULL;
+ if (IsIdentifier()) {
+ named_constructor = CurrentLiteral();
+ ConsumeToken();
+ }
+ // Resolve the type and optional identifier to a constructor or factory.
+ Class& type_class = Class::Handle(Z, type.type_class());
+ String& type_class_name = String::Handle(Z, type_class.Name());
+ *type_arguments = type.arguments();
+ String& constructor_name =
+ BuildConstructorName(type_class_name, named_constructor);
+ *constructor = type_class.LookupConstructor(constructor_name);
+ if (constructor->IsNull()) {
+ *constructor = type_class.LookupFactory(constructor_name);
+ ASSERT(!constructor->IsNull());
+ if (constructor->IsRedirectingFactory()) {
+ ClassFinalizer::ResolveRedirectingFactory(type_class, *constructor);
+ type = constructor->RedirectionType();
+ ASSERT(!type.IsMalformedOrMalbounded());
+ if (!type.IsInstantiated()) {
+ Error& error = Error::Handle(Z);
+ type ^= type.InstantiateFrom(*type_arguments, &error);
+ ASSERT(error.IsNull());
+ }
+ *type_arguments = type.arguments();
+ *constructor = constructor->RedirectionTarget();
+ }
+ }
+}
+
+
AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
TRACE_PARSER("ParseNewOperator");
const intptr_t new_pos = TokenPos();
@@ -12629,14 +12987,17 @@
intptr_t type_pos = TokenPos();
// Can't allocate const objects of a deferred type.
const bool allow_deferred_type = !is_const;
- const bool consume_unresolved_prefix = (LookaheadToken(3) == Token::kLT) ||
- (LookaheadToken(3) == Token::kPERIOD);
+ const Token::Kind la3 = LookaheadToken(3);
+ const bool consume_unresolved_prefix =
+ (la3 == Token::kLT) || (la3 == Token::kPERIOD) || (la3 == Token::kHASH);
+
LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z);
AbstractType& type = AbstractType::Handle(Z,
ParseType(ClassFinalizer::kCanonicalizeWellFormed,
allow_deferred_type,
consume_unresolved_prefix,
&prefix));
+
if (FLAG_load_deferred_eagerly &&
!prefix.IsNull() && prefix.is_deferred_load() && !prefix.is_loaded()) {
// Add runtime check.
@@ -12674,20 +13035,37 @@
String::Handle(Z, type_class.Name()).ToCString());
}
- // The grammar allows for an optional ('.' identifier)? after the type, which
- // is a named constructor. Note that we tell ParseType() above not to
- // consume it as part of a misinterpreted qualified identifier. Only a
- // valid library prefix is accepted as qualifier.
+ // The type can be followed by an optional named constructor identifier.
+ // Note that we tell ParseType() above not to consume it as part of
+ // a misinterpreted qualified identifier. Only a valid library
+ // prefix is accepted as qualifier.
String* named_constructor = NULL;
- if (CurrentToken() == Token::kPERIOD) {
+ const bool is_tearoff_expression = (CurrentToken() == Token::kHASH);
+ if (is_tearoff_expression) {
+ if (is_const) {
+ ReportError("tear-off closure not allowed with const allocation");
+ }
+ ConsumeToken();
+ if (IsIdentifier()) {
+ named_constructor = ExpectIdentifier("name of constructor expected");
+ }
+ } else if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
named_constructor = ExpectIdentifier("name of constructor expected");
}
// Parse constructor parameters.
- CheckToken(Token::kLPAREN);
intptr_t call_pos = TokenPos();
- ArgumentListNode* arguments = ParseActualParameters(NULL, is_const);
+ ArgumentListNode* arguments = NULL;
+ if (!is_tearoff_expression) {
+ CheckToken(Token::kLPAREN);
+ call_pos = TokenPos();
+ arguments = ParseActualParameters(NULL, is_const);
+ } else {
+ // Allocate dummy node with no arguments so we don't have to deal
+ // with the NULL corner case below.
+ arguments = new(Z) ArgumentListNode(TokenPos());
+ }
// Parsing is complete, so we can return a throw in case of a malformed or
// malbounded type or report a compile-time error if the constructor is const.
@@ -12805,10 +13183,10 @@
arguments_length -= 1;
}
}
+ ASSERT(!constructor.IsNull());
// It is ok to call a factory method of an abstract class, but it is
// a dynamic error to instantiate an abstract class.
- ASSERT(!constructor.IsNull());
if (type_class.is_abstract() && !constructor.IsFactory()) {
// Evaluate arguments before throwing.
LetNode* result = new(Z) LetNode(call_pos);
@@ -12826,6 +13204,32 @@
error_arguments));
return result;
}
+
+ type_arguments ^= type_arguments.Canonicalize();
+
+ if (is_tearoff_expression) {
+ const Function& tearoff_func = Function::ZoneHandle(Z,
+ BuildConstructorClosureFunction(constructor, new_pos));
+
+ // Local functions normally get parsed when the enclosing function is
+ // compiled. Since constructor tearoff closures don't get parsed here,
+ // we need to duplicate some of the side effects of parsing, namely
+ // creating a function scope, and capturing the instantiator of the
+ // enclosing function if necessary.
+ OpenFunctionBlock(tearoff_func);
+ // If there are type arguments in the tearoff expression that are
+ // not yet instantiated, capture the instantiator.
+ if (IsInstantiatorRequired() &&
+ !type_arguments.IsNull() && !type_arguments.IsInstantiated()) {
+ CaptureInstantiator();
+ }
+ SequenceNode* tearoff_body = CloseBlock();
+ ClosureNode* closure_obj =
+ new(Z) ClosureNode(new_pos, tearoff_func, NULL, tearoff_body->scope());
+ return closure_obj;
+ }
+
+ ASSERT(!is_tearoff_expression);
String& error_message = String::Handle(Z);
if (!constructor.AreValidArguments(arguments_length,
arguments->names(),
@@ -12857,7 +13261,7 @@
}
return ThrowTypeError(type_pos, type);
}
- type_arguments ^= type_arguments.Canonicalize();
+
// Make the constructor call.
AstNode* new_object = NULL;
if (is_const) {
@@ -13071,6 +13475,14 @@
} else if (IsIdentifier()) {
intptr_t qual_ident_pos = TokenPos();
const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z, ParsePrefix());
+ if (!prefix.IsNull()) {
+ if (CurrentToken() == Token::kHASH) {
+ // Closurization of top-level entity in prefix scope.
+ return new(Z) LiteralNode(qual_ident_pos, prefix);
+ } else {
+ ExpectToken(Token::kPERIOD);
+ }
+ }
String& ident = *CurrentLiteral();
ConsumeToken();
if (prefix.IsNull()) {
@@ -13287,7 +13699,7 @@
script_, expr_pos,
"error evaluating constant expression");
}
- ASSERT(result.IsInstance());
+ ASSERT(result.IsInstance() || result.IsNull());
Instance& value = Instance::ZoneHandle(Z);
value ^= result.raw();
value = TryCanonicalize(value, TokenPos());
@@ -13432,6 +13844,16 @@
ConsumeToken(); // Skip new or const keyword.
if (IsIdentifier()) {
SkipType(false);
+ if (CurrentToken() == Token::kPERIOD) {
+ ConsumeToken();
+ ExpectIdentifier("identifier expected");
+ } else if (CurrentToken() == Token::kHASH) {
+ ConsumeToken();
+ if (IsIdentifier()) {
+ ConsumeToken();
+ }
+ return;
+ }
if (CurrentToken() == Token::kLPAREN) {
SkipActualParameters();
return;
@@ -13550,6 +13972,16 @@
void Parser::SkipPostfixExpr() {
SkipPrimary();
+ if (CurrentToken() == Token::kHASH) {
+ if (IsIdentifier()) {
+ ConsumeToken();
+ SkipIf(Token::kASSIGN);
+ } else if (Token::CanBeOverloaded(CurrentToken())) {
+ ConsumeToken();
+ } else {
+ ReportError("identifier or operator expected");
+ }
+ }
SkipSelectors();
if (IsIncrementOperator(CurrentToken())) {
ConsumeToken();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 9cab860..2e74b1c 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -41,7 +41,7 @@
class ParsedFunction : public ZoneAllocated {
public:
ParsedFunction(Thread* thread, const Function& function)
- : isolate_(thread->isolate()),
+ : thread_(thread),
function_(function),
code_(Code::Handle(zone(), function.unoptimized_code())),
node_sequence_(NULL),
@@ -150,11 +150,11 @@
void record_await() { have_seen_await_expr_ = true; }
bool have_seen_await() const { return have_seen_await_expr_; }
- Isolate* isolate() const { return isolate_; }
- Zone* zone() const { return isolate()->current_zone(); }
+ Isolate* isolate() const { return thread_->isolate(); }
+ Zone* zone() const { return thread_->zone(); }
private:
- Isolate* isolate_;
+ Thread* thread_;
const Function& function_;
Code& code_;
SequenceNode* node_sequence_;
@@ -509,6 +509,8 @@
AstNode* ParseSuperOperator();
AstNode* BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super);
+ static bool ParseFormalParameters(const Function& func, ParamList* params);
+
static void SetupDefaultsForOptionalParams(const ParamList* params,
Array* default_values);
ClosureNode* CreateImplicitClosureNode(const Function& func,
@@ -536,6 +538,8 @@
Array* default_values);
SequenceNode* ParseImplicitClosure(const Function& func,
Array* default_values);
+ SequenceNode* ParseConstructorClosure(const Function& func,
+ Array* default_values);
void BuildDispatcherScope(const Function& func,
const ArgumentsDescriptor& desc,
@@ -694,6 +698,7 @@
AstNode* ParseUnaryExpr();
AstNode* ParsePostfixExpr();
AstNode* ParseSelectors(AstNode* primary, bool is_cascade);
+ AstNode* ParseClosurization(AstNode* primary);
AstNode* ParseCascades(AstNode* expr);
AstNode* ParsePrimary();
AstNode* ParseStringLiteral(bool allow_interpolation);
@@ -706,7 +711,12 @@
AstNode* ParseMapLiteral(intptr_t type_pos,
bool is_const,
const TypeArguments& type_arguments);
+
+ RawFunction* BuildConstructorClosureFunction(const Function& ctr,
+ intptr_t token_pos);
AstNode* ParseNewOperator(Token::Kind op_kind);
+ void ParseConstructorClosurization(Function* constructor,
+ TypeArguments* type_arguments);
// An implicit argument, if non-null, is prepended to the returned list.
ArgumentListNode* ParseActualParameters(ArgumentListNode* implicit_arguments,
@@ -807,9 +817,10 @@
RawInstance* TryCanonicalize(const Instance& instance, intptr_t token_pos);
Isolate* isolate() const { return isolate_; }
- Zone* zone() const { return isolate()->current_zone(); }
+ Zone* zone() const { return thread_->zone(); }
Isolate* isolate_; // Cached current isolate.
+ Thread* thread_;
Script& script_;
TokenStream::Iterator tokens_iterator_;
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
new file mode 100644
index 0000000..52287f3
--- /dev/null
+++ b/runtime/vm/precompiler.cc
@@ -0,0 +1,594 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/precompiler.h"
+
+#include "vm/compiler.h"
+#include "vm/isolate.h"
+#include "vm/longjump.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/resolver.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+
+#define I (isolate())
+#define Z (zone())
+
+
+DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
+
+
+static void Jump(const Error& error) {
+ Isolate::Current()->long_jump_base()->Jump(1, error);
+}
+
+
+RawError* Precompiler::CompileAll() {
+ LongJumpScope jump;
+ if (setjmp(*jump.Set()) == 0) {
+ Precompiler precompiler(Thread::Current());
+ precompiler.DoCompileAll();
+ return Error::null();
+ } else {
+ Isolate* isolate = Isolate::Current();
+ const Error& error = Error::Handle(isolate->object_store()->sticky_error());
+ isolate->object_store()->clear_sticky_error();
+ return error.raw();
+ }
+}
+
+
+Precompiler::Precompiler(Thread* thread) :
+ thread_(thread),
+ zone_(thread->zone()),
+ isolate_(thread->isolate()),
+ changed_(false),
+ function_count_(0),
+ class_count_(0),
+ libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())),
+ pending_functions_(GrowableObjectArray::Handle(Z,
+ GrowableObjectArray::New())),
+ collected_closures_(GrowableObjectArray::Handle(Z, I->collected_closures())),
+ sent_selectors_(GrowableObjectArray::Handle(Z, GrowableObjectArray::New())),
+ error_(Error::Handle(Z)) {
+}
+
+
+void Precompiler::DoCompileAll() {
+ // Drop all existing code so we can use the presence of code as an indicator
+ // that we have already looked for the function's callees.
+ ClearAllCode();
+
+ // Start with the allocations and invocations that happen from C++.
+ AddRoots();
+
+ // TODO(rmacnak): Eagerly add field-invocation functions to all signature
+ // classes so closure calls don't go through the runtime.
+
+ // Compile newly found targets and add their callees until we reach a fixed
+ // point.
+ Iterate();
+
+ CleanUp();
+
+ if (FLAG_trace_precompiler) {
+ OS::Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
+ " %" Pd " dynamic selectors\n",
+ function_count_,
+ class_count_,
+ sent_selectors_.Length());
+ }
+
+ I->set_compilation_allowed(false);
+}
+
+
+void Precompiler::ClearAllCode() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& functions = Array::Handle(Z);
+ Function& function = Function::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();
+ error_ = cls.EnsureIsFinalized(I);
+ if (!error_.IsNull()) {
+ Jump(error_);
+ }
+ }
+ }
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ functions = cls.functions();
+ for (intptr_t i = 0; i < functions.Length(); i++) {
+ function ^= functions.At(i);
+ function.ClearCode();
+ }
+ }
+ }
+}
+
+
+void Precompiler::AddRoots() {
+ // Note that <rootlibrary>.main is not a root. The appropriate main will be
+ // discovered through _getMainClosure.
+
+ AddSelector(Symbols::NoSuchMethod());
+
+ AddSelector(Symbols::Call()); // For speed, not correctness.
+
+ // Allocated from C++.
+ static const intptr_t kExternallyAllocatedCids[] = {
+ kBoolCid,
+ kNullCid,
+
+ kSmiCid,
+ kMintCid,
+ kBigintCid,
+ kDoubleCid,
+
+ kOneByteStringCid,
+ kTwoByteStringCid,
+ kExternalOneByteStringCid,
+ kExternalTwoByteStringCid,
+
+ kArrayCid,
+ kImmutableArrayCid,
+ kGrowableObjectArrayCid,
+ kLinkedHashMapCid,
+
+ kTypedDataUint8ClampedArrayCid,
+ kTypedDataUint8ArrayCid,
+ kTypedDataUint16ArrayCid,
+ kTypedDataUint32ArrayCid,
+ kTypedDataUint64ArrayCid,
+
+ kTypedDataInt8ArrayCid,
+ kTypedDataInt16ArrayCid,
+ kTypedDataInt32ArrayCid,
+ kTypedDataInt64ArrayCid,
+
+ kExternalTypedDataUint8ArrayCid,
+
+ kTypedDataFloat32ArrayCid,
+ kTypedDataFloat64ArrayCid,
+
+ kTypedDataFloat32x4ArrayCid,
+ kTypedDataInt32x4ArrayCid,
+ kTypedDataFloat64x2ArrayCid,
+
+ kInt32x4Cid,
+ kFloat32x4Cid,
+ kFloat64x2Cid,
+
+ kTypeCid,
+ kTypeRefCid,
+ kTypeParameterCid,
+ kBoundedTypeCid,
+ kLibraryPrefixCid,
+
+ kJSRegExpCid,
+ kUserTagCid,
+ kStacktraceCid,
+ kWeakPropertyCid,
+ kCapabilityCid,
+ ReceivePort::kClassId,
+ SendPort::kClassId,
+
+ kIllegalCid
+ };
+
+ Class& cls = Class::Handle(Z);
+ for (intptr_t i = 0; kExternallyAllocatedCids[i] != kIllegalCid; i++) {
+ cls = isolate()->class_table()->At(kExternallyAllocatedCids[i]);
+ AddClass(cls);
+ }
+
+ static const struct {
+ const char* library_;
+ const char* class_;
+ const char* function_;
+ } kExternallyCalled[] = {
+ { "dart:_builtin", "::", "_getMainClosure" },
+ { "dart:_builtin", "::", "_getPrintClosure" },
+ { "dart:_builtin", "::", "_getUriBaseClosure" },
+ { "dart:_builtin", "::", "_resolveUri" },
+ { "dart:_builtin", "::", "_setWorkingDirectory" },
+ { "dart:async", "::", "_setScheduleImmediateClosure" },
+ { "dart:core", "_InternalError", "_InternalError." },
+ { "dart:core", "_InvocationMirror", "_allocateInvocationMirror" },
+ { "dart:io", "::", "_makeUint8ListView" },
+ { "dart:io", "::", "_makeDatagram" },
+ { "dart:io", "CertificateException", "CertificateException." },
+ { "dart:io", "HandshakeException", "HandshakeException." },
+ { "dart:io", "TlsException", "TlsException." },
+ { "dart:io", "X509Certificate", "X509Certificate." },
+ { "dart:io", "_ExternalBuffer", "set:data" },
+ { "dart:io", "_Platform", "set:_nativeScript" },
+ { "dart:io", "_ProcessStartStatus", "set:_errorCode" },
+ { "dart:io", "_ProcessStartStatus", "set:_errorMessage" },
+ { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" },
+ { "dart:io", "_SecureFilterImpl", "get:SIZE" },
+ { "dart:isolate", "::", "_getIsolateScheduleImmediateClosure" },
+ { "dart:isolate", "::", "_startMainIsolate" },
+ { "dart:isolate", "_RawReceivePortImpl", "_handleMessage" },
+ { "dart:isolate", "_RawReceivePortImpl", "_lookupHandler" },
+ { "dart:vmservice", "::", "_registerIsolate" },
+ { "dart:vmservice", "::", "boot" },
+ { "dart:vmservice_io", "::", "_addResource" },
+ { "dart:vmservice_io", "::", "main" },
+
+ // Cf. Exceptions::Create
+ { "dart:core", "RangeError", "RangeError." },
+ { "dart:core", "RangeError", "RangeError.range" },
+ { "dart:core", "ArgumentError", "ArgumentError." },
+ { "dart:core", "NoSuchMethodError", "NoSuchMethodError._withType" },
+ { "dart:core", "FormatException", "FormatException." },
+ { "dart:core", "UnsupportedError", "UnsupportedError." },
+ { "dart:core", "NullThrownError", "NullThrownError." },
+ { "dart:isolate", "IsolateSpawnException", "IsolateSpawnException." },
+ { "dart:isolate", "_IsolateUnhandledException",
+ "_IsolateUnhandledException." },
+ { "dart:core", "_JavascriptIntegerOverflowError",
+ "_JavascriptIntegerOverflowError." },
+ { "dart:core", "_JavascriptCompatibilityError",
+ "_JavascriptCompatibilityError." },
+ { "dart:core", "AssertionError", "AssertionError." },
+ { "dart:core", "_CastError", "_CastError._create" },
+ { "dart:core", "_TypeError", "_TypeError._create" },
+ { "dart:core", "FallThroughError", "FallThroughError._create" },
+ { "dart:core", "AbstractClassInstantiationError",
+ "AbstractClassInstantiationError._create" },
+ { "dart:core", "CyclicInitializationError",
+ "CyclicInitializationError." },
+ { "dart:core", "StackOverflowError", "StackOverflowError." },
+ { "dart:core", "OutOfMemoryError", "OutOfMemoryError." },
+ { NULL, NULL, NULL }
+ };
+
+ Library& lib = Library::Handle(Z);
+ Function& func = Function::Handle(Z);
+ String& library_name = String::Handle(Z);
+ String& class_name = String::Handle(Z);
+ String& function_name = String::Handle(Z);
+ for (intptr_t i = 0; kExternallyCalled[i].library_ != NULL; i++) {
+ library_name = Symbols::New(kExternallyCalled[i].library_);
+ class_name = Symbols::New(kExternallyCalled[i].class_);
+ function_name = Symbols::New(kExternallyCalled[i].function_);
+
+ lib = Library::LookupLibrary(library_name);
+ if (lib.IsNull()) {
+ if (FLAG_trace_precompiler) {
+ OS::Print("WARNING: Missing %s\n", kExternallyCalled[i].library_);
+ }
+ continue;
+ }
+
+ if (class_name.raw() == Symbols::TopLevel().raw()) {
+ func = lib.LookupFunctionAllowPrivate(function_name);
+ } else {
+ cls = lib.LookupClassAllowPrivate(class_name);
+ if (cls.IsNull()) {
+ if (FLAG_trace_precompiler) {
+ OS::Print("WARNING: Missing %s %s\n",
+ kExternallyCalled[i].library_,
+ kExternallyCalled[i].class_);
+ }
+ continue;
+ }
+
+ ASSERT(!cls.IsNull());
+ func = cls.LookupFunctionAllowPrivate(function_name);
+ }
+
+ if (func.IsNull()) {
+ if (FLAG_trace_precompiler) {
+ OS::Print("WARNING: Missing %s %s %s\n",
+ kExternallyCalled[i].library_,
+ kExternallyCalled[i].class_,
+ kExternallyCalled[i].function_);
+ }
+ continue;
+ }
+
+ AddFunction(func);
+ }
+}
+
+
+void Precompiler::Iterate() {
+ Function& function = Function::Handle(Z);
+
+ while (changed_) {
+ changed_ = false;
+
+ while (pending_functions_.Length() > 0) {
+ function ^= pending_functions_.RemoveLast();
+ ProcessFunction(function);
+ }
+
+ CheckForNewDynamicFunctions();
+
+ // Drain collected_closures last because additions to this list come from
+ // outside the Precompiler and so do not flip our changed_ flag.
+ while (collected_closures_.Length() > 0) {
+ function ^= collected_closures_.RemoveLast();
+ ProcessFunction(function);
+ }
+ }
+}
+
+
+void Precompiler::CleanUp() {
+ I->set_collected_closures(GrowableObjectArray::Handle(Z));
+
+ // TODO(rmacnak): Drop functions without code, classes without functions, etc.
+}
+
+
+void Precompiler::ProcessFunction(const Function& function) {
+ if (!function.HasCode()) {
+ function_count_++;
+
+ if (FLAG_trace_precompiler) {
+ OS::Print("Precompiling %" Pd " %s (%" Pd ", %s)\n",
+ function_count_,
+ function.ToLibNamePrefixedQualifiedCString(),
+ function.token_pos(),
+ Function::KindToCString(function.kind()));
+ }
+
+ ASSERT(!function.is_abstract());
+ ASSERT(!function.IsRedirectingFactory());
+
+ error_ = Compiler::CompileFunction(thread_, function);
+ if (!error_.IsNull()) {
+ Jump(error_);
+ }
+ }
+
+ ASSERT(function.HasCode());
+ AddCalleesOf(function);
+}
+
+
+void Precompiler::AddCalleesOf(const Function& function) {
+ ASSERT(function.HasCode());
+
+ const Code& code = Code::Handle(Z, function.CurrentCode());
+
+ const Array& table = Array::Handle(Z, code.static_calls_target_table());
+ Object& entry = Object::Handle(Z);
+ Function& target = Function::Handle(Z);
+ for (intptr_t i = 0; i < table.Length(); i++) {
+ entry = table.At(i);
+ if (entry.IsFunction()) {
+ target ^= table.At(i);
+ AddFunction(target);
+ }
+ }
+
+#if defined(TARGET_ARCH_IA32)
+ FATAL("Callee scanning unimplemented for IA32");
+#endif
+
+ const ObjectPool& pool = ObjectPool::Handle(Z, code.GetObjectPool());
+ ICData& call_site = ICData::Handle(Z);
+ String& selector = String::Handle(Z);
+ Field& field = Field::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ for (intptr_t i = 0; i < pool.Length(); i++) {
+ if (pool.InfoAt(i) == ObjectPool::kTaggedObject) {
+ entry = pool.ObjectAt(i);
+ if (entry.IsICData()) {
+ call_site ^= entry.raw();
+ if (call_site.NumberOfChecks() == 1) {
+ // Probably a static call.
+ target = call_site.GetTargetAt(0);
+ AddFunction(target);
+ if (!target.is_static()) {
+ // Super call (should not enqueue selector) or dynamic call with a
+ // CHA prediction (should enqueue selector).
+ selector = call_site.target_name();
+ AddSelector(selector);
+ }
+ } else {
+ // A dynamic call.
+ selector = call_site.target_name();
+ AddSelector(selector);
+ }
+ } else if (entry.IsField()) {
+ // Potential need for field initializer.
+ field ^= entry.raw();
+ AddField(field);
+ } else if (entry.IsInstance()) {
+ // Potential const object.
+ cls = entry.clazz();
+ AddClass(cls);
+ }
+ }
+ }
+}
+
+
+void Precompiler::AddField(const Field& field) {
+ if (field.is_static()) {
+ // Potential const object. Uninitialized field will harmlessly do a
+ // redundant add of the Null class.
+ const Object& value = Object::Handle(Z, field.value());
+ const Class& cls = Class::Handle(Z, value.clazz());
+ AddClass(cls);
+
+ if (field.has_initializer()) {
+ if (field.initializer() != Function::null()) return;
+
+ if (FLAG_trace_precompiler) {
+ OS::Print("Precompiling initializer for %s\n", field.ToCString());
+ }
+ Compiler::CompileStaticInitializer(field);
+
+ const Function& function = Function::Handle(Z, field.initializer());
+ AddCalleesOf(function);
+ }
+ }
+}
+
+
+void Precompiler::AddFunction(const Function& function) {
+ if (function.HasCode()) return;
+
+ pending_functions_.Add(function);
+ changed_ = true;
+}
+
+
+bool Precompiler::IsSent(const String& selector) {
+ ASSERT(selector.IsSymbol());
+
+ // TODO(rmacnak): Use a proper set.
+ for (intptr_t i = 0; i < sent_selectors_.Length(); i++) {
+ if (sent_selectors_.At(i) == selector.raw()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void Precompiler::AddSelector(const String& selector) {
+ if (!IsSent(selector)) {
+ if (FLAG_trace_precompiler) {
+ OS::Print("Enqueueing selector %" Pd " %s\n",
+ sent_selectors_.Length(),
+ selector.ToCString());
+ }
+
+ sent_selectors_.Add(selector);
+ changed_ = true;
+
+ if (!Field::IsGetterName(selector) &&
+ !Field::IsSetterName(selector)) {
+ // Regular method may be call-through-getter.
+ // TODO(rmacnak): Do not create the symbol if it does not already exist.
+ String& getter = String::Handle(Field::GetterName(selector));
+ getter = Symbols::New(getter);
+ AddSelector(getter);
+ }
+ }
+}
+
+
+void Precompiler::AddClass(const Class& cls) {
+ if (cls.is_allocated()) return;
+
+ class_count_++;
+ cls.set_is_allocated();
+ changed_ = true;
+
+ if (FLAG_trace_precompiler) {
+ OS::Print("Allocation %" Pd " %s\n", class_count_, cls.ToCString());
+ }
+
+ const Class& superclass = Class::Handle(cls.SuperClass());
+ if (!superclass.IsNull()) {
+ AddClass(superclass);
+ }
+}
+
+
+void Precompiler::CheckForNewDynamicFunctions() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& functions = Array::Handle(Z);
+ Function& function = Function::Handle(Z);
+ String& selector = String::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.is_allocated()) {
+ bool has_compiled_constructor = false;
+ if (cls.allocation_stub() != Code::null()) {
+ // Regular objects.
+ has_compiled_constructor = true;
+ } else if (cls.is_synthesized_class()) {
+ // Enums.
+ has_compiled_constructor = true;
+ } else {
+ // Objects only allocated via const constructors, and not stored in a
+ // static field or code.
+ // E.g. A in
+ // class A {
+ // const A();
+ // toString() => "Don't drop me!";
+ // }
+ // class B {
+ // const a = const A();
+ // const B();
+ // static const theB = const B();
+ // }
+ // main() => print(B.theB.a);
+ functions = cls.functions();
+ for (intptr_t k = 0; k < functions.Length(); k++) {
+ function ^= functions.At(k);
+ if (function.IsGenerativeConstructor() &&
+ function.HasCode()) {
+ has_compiled_constructor = true;
+ break;
+ }
+ }
+ }
+ if (!has_compiled_constructor) {
+ continue;
+ }
+ AddClass(cls);
+ }
+
+ functions = cls.functions();
+ for (intptr_t k = 0; k < functions.Length(); k++) {
+ function ^= functions.At(k);
+
+ if (function.is_static() || function.is_abstract()) continue;
+
+ // Don't bail out early if there is already code because we may discover
+ // the corresponding getter selector is sent in some later iteration.
+ // if (function.HasCode()) continue;
+
+ selector = function.name();
+ if (IsSent(selector)) {
+ AddFunction(function);
+ }
+
+ if (function.kind() == RawFunction::kRegularFunction &&
+ !Field::IsGetterName(selector) &&
+ !Field::IsSetterName(selector)) {
+ // TODO(rmacnak): Do not create the symbol if it does not already
+ // exist.
+ selector = Field::GetterName(selector);
+ selector = Symbols::New(selector);
+ if (IsSent(selector)) {
+ function = function.ImplicitClosureFunction();
+ AddFunction(function);
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace dart
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
new file mode 100644
index 0000000..158a8ba
--- /dev/null
+++ b/runtime/vm/precompiler.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_PRECOMPILER_H_
+#define VM_PRECOMPILER_H_
+
+#include "vm/allocation.h"
+
+namespace dart {
+
+// Forward declarations.
+class Class;
+class Error;
+class Field;
+class Function;
+class GrowableObjectArray;
+class RawError;
+class String;
+
+class Precompiler : public ValueObject {
+ public:
+ static RawError* CompileAll();
+
+ private:
+ explicit Precompiler(Thread* thread);
+
+ void DoCompileAll();
+ void ClearAllCode();
+ void AddRoots();
+ void Iterate();
+ void CleanUp();
+
+ void AddCalleesOf(const Function& function);
+ void AddField(const Field& field);
+ void AddFunction(const Function& function);
+ void AddClass(const Class& cls);
+ void AddSelector(const String& selector);
+ bool IsSent(const String& selector);
+
+ void ProcessFunction(const Function& function);
+ void CheckForNewDynamicFunctions();
+
+ Thread* thread() const { return thread_; }
+ Zone* zone() const { return zone_; }
+ Isolate* isolate() const { return isolate_; }
+
+ Thread* thread_;
+ Zone* zone_;
+ Isolate* isolate_;
+
+ bool changed_;
+ intptr_t function_count_;
+ intptr_t class_count_;
+
+ const GrowableObjectArray& libraries_;
+ const GrowableObjectArray& pending_functions_;
+ const GrowableObjectArray& collected_closures_;
+ const GrowableObjectArray& sent_selectors_;
+ Error& error_;
+};
+
+} // namespace dart
+
+#endif // VM_PRECOMPILER_H_
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index b674952..ff0edc7 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -439,15 +439,13 @@
// Executing Dart code, walk the stack.
class ProfilerDartStackWalker : public ValueObject {
public:
- ProfilerDartStackWalker(Isolate* isolate,
- Sample* sample,
+ ProfilerDartStackWalker(Sample* sample,
uword stack_lower,
uword stack_upper,
uword pc,
uword fp,
uword sp)
- : isolate_(isolate),
- sample_(sample),
+ : sample_(sample),
stack_upper_(stack_upper),
stack_lower_(stack_lower) {
ASSERT(sample_ != NULL);
@@ -464,7 +462,7 @@
}
ASSERT(ValidFramePointer());
uword return_pc = InitialReturnAddress();
- if (StubCode::InInvocationStubForIsolate(isolate_, return_pc)) {
+ if (StubCode::InInvocationStub(return_pc)) {
// Edge case- we have called out from the Invocation Stub but have not
// created the stack frame of the callee. Attempt to locate the exit
// frame before walking the stack.
@@ -488,16 +486,14 @@
if (!ValidFramePointer()) {
return false;
}
- if (StubCode::InInvocationStubForIsolate(isolate_,
- reinterpret_cast<uword>(pc_))) {
+ if (StubCode::InInvocationStub(reinterpret_cast<uword>(pc_))) {
// In invocation stub.
return NextExit();
}
// In regular Dart frame.
uword* new_pc = CallerPC();
// Check if we've moved into the invocation stub.
- if (StubCode::InInvocationStubForIsolate(isolate_,
- reinterpret_cast<uword>(new_pc))) {
+ if (StubCode::InInvocationStub(reinterpret_cast<uword>(new_pc))) {
// New PC is inside invocation stub, skip.
return NextExit();
}
@@ -585,7 +581,6 @@
uword* pc_;
uword* fp_;
uword* sp_;
- Isolate* isolate_;
Sample* sample_;
const uword stack_upper_;
uword stack_lower_;
@@ -827,8 +822,7 @@
}
ASSERT(isolate != Dart::vm_isolate());
- const bool exited_dart_code = (isolate->stub_code() != NULL) &&
- (isolate->top_exit_frame_info() != 0) &&
+ const bool exited_dart_code = (isolate->top_exit_frame_info() != 0) &&
(isolate->vm_tag() != VMTag::kDartTagId);
if (!exited_dart_code) {
@@ -883,11 +877,9 @@
ASSERT(isolate != Dart::vm_isolate());
- const bool exited_dart_code = (isolate->stub_code() != NULL) &&
- (isolate->top_exit_frame_info() != 0) &&
+ const bool exited_dart_code = (isolate->top_exit_frame_info() != 0) &&
(isolate->vm_tag() != VMTag::kDartTagId);
- const bool in_dart_code = (isolate->stub_code() != NULL) &&
- (isolate->top_exit_frame_info() == 0) &&
+ const bool in_dart_code = (isolate->top_exit_frame_info() == 0) &&
(isolate->vm_tag() == VMTag::kDartTagId);
uintptr_t sp = 0;
@@ -1018,8 +1010,7 @@
ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample);
- ProfilerDartStackWalker dart_stack_walker(isolate,
- sample,
+ ProfilerDartStackWalker dart_stack_walker(sample,
stack_lower,
stack_upper,
pc,
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index bf47f20..872b600 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -97,7 +97,8 @@
table_index_(table_index),
profile_codes_(0),
exclusive_ticks_(0),
- inclusive_ticks_(0) {
+ inclusive_ticks_(0),
+ inclusive_serial_(-1) {
ASSERT((kind_ != kDartFunction) || !function_.IsNull());
ASSERT((kind_ != kDartFunction) || (table_index_ >= 0));
ASSERT(profile_codes_.length() == 0);
@@ -117,14 +118,14 @@
void ProfileFunction::Tick(bool exclusive, intptr_t inclusive_serial) {
if (exclusive) {
exclusive_ticks_++;
- } else {
- if (inclusive_serial_ == inclusive_serial) {
- // Already ticket.
- return;
- }
- inclusive_serial_ = inclusive_serial;
- inclusive_ticks_++;
}
+ // Fall through and tick inclusive count too.
+ if (inclusive_serial_ == inclusive_serial) {
+ // Already ticked.
+ return;
+ }
+ inclusive_serial_ = inclusive_serial;
+ inclusive_ticks_++;
}
@@ -268,17 +269,19 @@
void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) {
+ // If exclusive is set, tick it.
if (exclusive) {
exclusive_ticks_++;
- } else {
- if (inclusive_serial_ == serial) {
- // Already ticked for this sample.
- return;
- }
- inclusive_serial_ = serial;
- inclusive_ticks_++;
+ TickAddress(pc, true);
}
- TickAddress(pc, exclusive);
+ // Fall through and tick inclusive count too.
+ if (inclusive_serial_ == serial) {
+ // Already gave inclusive tick for this sample.
+ return;
+ }
+ inclusive_serial_ = serial;
+ inclusive_ticks_++;
+ TickAddress(pc, false);
}
@@ -578,11 +581,34 @@
ASSERT(tag_name != NULL);
SetName(tag_name);
} else {
- if (start() == VMTag::kRootTagId) {
- SetName("Root");
- } else {
- ASSERT(start() == VMTag::kTruncatedTagId);
- SetName("[Truncated]");
+ switch (start()) {
+ case VMTag::kRootTagId:
+ SetName("Root");
+ break;
+ case VMTag::kTruncatedTagId:
+ SetName("[Truncated]");
+ break;
+ case VMTag::kNoneCodeTagId:
+ SetName("[No Code]");
+ break;
+ case VMTag::kOptimizedCodeTagId:
+ SetName("[Optimized Code]");
+ break;
+ case VMTag::kUnoptimizedCodeTagId:
+ SetName("[Unoptimized Code]");
+ break;
+ case VMTag::kNativeCodeTagId:
+ SetName("[Native Code]");
+ break;
+ case VMTag::kInlineStartCodeTagId:
+ SetName("[Inline Start]");
+ break;
+ case VMTag::kInlineEndCodeTagId:
+ SetName("[Inline End]");
+ break;
+ default:
+ UNIMPLEMENTED();
+ break;
}
}
}
@@ -948,20 +974,34 @@
class ProfileBuilder : public ValueObject {
public:
+ enum ProfileInfoKind {
+ kNone,
+ kOptimized,
+ kUnoptimized,
+ kNative,
+ kInlineStart,
+ kInlineFinish,
+ kNumProfileInfoKind,
+ };
+
ProfileBuilder(Isolate* isolate,
SampleFilter* filter,
Profile::TagOrder tag_order,
+ intptr_t extra_tags,
Profile* profile)
: isolate_(isolate),
vm_isolate_(Dart::vm_isolate()),
filter_(filter),
tag_order_(tag_order),
+ extra_tags_(extra_tags),
profile_(profile),
deoptimized_code_(new DeoptimizedCodeSet(isolate)),
null_code_(Code::ZoneHandle()),
null_function_(Function::ZoneHandle()),
tick_functions_(false),
- samples_(NULL) {
+ inclusive_tree_(false),
+ samples_(NULL),
+ info_kind_(kNone) {
ASSERT(profile_ != NULL);
}
@@ -982,6 +1022,12 @@
}
private:
+ // Returns true if |frame_index| in |sample| is using CPU.
+ static bool IsExecutingFrame(ProcessedSample* sample, intptr_t frame_index) {
+ return (frame_index == 0) && (sample->first_frame_executing() ||
+ sample->IsAllocationSample());
+ }
+
static bool IsInclusiveTrie(Profile::TrieKind kind) {
return (kind == Profile::kInclusiveFunction) ||
(kind == Profile::kInclusiveCode);
@@ -995,6 +1041,12 @@
// Register some synthetic tags.
RegisterProfileCodeTag(VMTag::kRootTagId);
RegisterProfileCodeTag(VMTag::kTruncatedTagId);
+ RegisterProfileCodeTag(VMTag::kNoneCodeTagId);
+ RegisterProfileCodeTag(VMTag::kOptimizedCodeTagId);
+ RegisterProfileCodeTag(VMTag::kUnoptimizedCodeTagId);
+ RegisterProfileCodeTag(VMTag::kNativeCodeTagId);
+ RegisterProfileCodeTag(VMTag::kInlineStartCodeTagId);
+ RegisterProfileCodeTag(VMTag::kInlineEndCodeTagId);
}
void FilterSamples() {
@@ -1021,8 +1073,10 @@
void BuildCodeTable() {
ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler);
- for (intptr_t i = 0; i < samples_->length(); i++) {
- ProcessedSample* sample = samples_->At(i);
+ for (intptr_t sample_index = 0;
+ sample_index < samples_->length();
+ sample_index++) {
+ ProcessedSample* sample = samples_->At(sample_index);
const int64_t timestamp = sample->timestamp();
// This is our first pass over the sample buffer, use this as an
@@ -1041,12 +1095,14 @@
// Make sure that a ProfileCode objects exist for all pcs in the sample
// and tick each one.
- for (intptr_t i = 0; i < sample->length(); i++) {
- const uword pc = sample->At(i);
+ for (intptr_t frame_index = 0;
+ frame_index < sample->length();
+ frame_index++) {
+ const uword pc = sample->At(frame_index);
ASSERT(pc != 0);
ProfileCode* code = RegisterProfileCode(pc, timestamp);
ASSERT(code != NULL);
- code->Tick(pc, (i == 0), i);
+ code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index);
}
}
}
@@ -1113,7 +1169,8 @@
void BuildCodeTrie(Profile::TrieKind kind) {
ProfileCodeTrieNode* root =
new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId));
- if (IsInclusiveTrie(kind)) {
+ inclusive_tree_ = IsInclusiveTrie(kind);
+ if (inclusive_tree_) {
BuildInclusiveCodeTrie(root);
} else {
BuildExclusiveCodeTrie(root);
@@ -1125,8 +1182,10 @@
void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) {
ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie",
FLAG_trace_profiler);
- for (intptr_t i = 0; i < samples_->length(); i++) {
- ProcessedSample* sample = samples_->At(i);
+ for (intptr_t sample_index = 0;
+ sample_index < samples_->length();
+ sample_index++) {
+ ProcessedSample* sample = samples_->At(sample_index);
// Tick the root.
ProfileCodeTrieNode* current = root;
@@ -1135,17 +1194,27 @@
// VM & User tags.
current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
+ ResetKind();
+
// Truncated tag.
if (sample->truncated()) {
current = AppendTruncatedTag(current);
}
// Walk the sampled PCs.
- for (intptr_t j = sample->length() - 1; j >= 0; j--) {
- ASSERT(sample->At(j) != 0);
+ Code& code = Code::Handle();
+ for (intptr_t frame_index = sample->length() - 1;
+ frame_index >= 0;
+ frame_index--) {
+ ASSERT(sample->At(frame_index) != 0);
intptr_t index =
- GetProfileCodeIndex(sample->At(j), sample->timestamp());
+ GetProfileCodeIndex(sample->At(frame_index), sample->timestamp());
ASSERT(index >= 0);
+ ProfileCode* profile_code =
+ GetProfileCode(sample->At(frame_index), sample->timestamp());
+ ASSERT(profile_code->code_table_index() == index);
+ code ^= profile_code->code();
+ current = AppendKind(code, current);
current = current->GetChild(index);
current->Tick();
}
@@ -1155,8 +1224,10 @@
void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) {
ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie",
FLAG_trace_profiler);
- for (intptr_t i = 0; i < samples_->length(); i++) {
- ProcessedSample* sample = samples_->At(i);
+ for (intptr_t sample_index = 0;
+ sample_index < samples_->length();
+ sample_index++) {
+ ProcessedSample* sample = samples_->At(sample_index);
// Tick the root.
ProfileCodeTrieNode* current = root;
@@ -1165,28 +1236,27 @@
// VM & User tags.
current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
- // Walk the sampled PCs.
- for (intptr_t j = 0; j < sample->length(); j++) {
- ASSERT(sample->At(j) != 0);
- intptr_t index =
- GetProfileCodeIndex(sample->At(j), sample->timestamp());
- ASSERT(index >= 0);
- current = current->GetChild(index);
+ ResetKind();
- if (j == 0) {
- // Executing PC.
- if (!sample->first_frame_executing() || vm_tags_emitted()) {
- // Only tick if this isn't an exit frame or VM tags are emitted.
- current->Tick();
- }
- } else {
- // Caller PCs.
+ // Walk the sampled PCs.
+ Code& code = Code::Handle();
+ for (intptr_t frame_index = 0;
+ frame_index < sample->length();
+ frame_index++) {
+ ASSERT(sample->At(frame_index) != 0);
+ intptr_t index =
+ GetProfileCodeIndex(sample->At(frame_index), sample->timestamp());
+ ASSERT(index >= 0);
+ ProfileCode* profile_code =
+ GetProfileCode(sample->At(frame_index), sample->timestamp());
+ ASSERT(profile_code->code_table_index() == index);
+ code ^= profile_code->code();
+ current = current->GetChild(index);
+ if (ShouldTickNode(sample, frame_index)) {
current->Tick();
}
-
- current->Tick();
+ current = AppendKind(code, current);
}
-
// Truncated tag.
if (sample->truncated()) {
current = AppendTruncatedTag(current);
@@ -1199,9 +1269,10 @@
new ProfileFunctionTrieNode(
GetProfileFunctionTagIndex(VMTag::kRootTagId));
// We tick the functions while building the trie, but, we don't want to do
- // it for both tries, just one.
- tick_functions_ = IsInclusiveTrie(kind);
- if (IsInclusiveTrie(kind)) {
+ // it for both tries, just the exclusive trie.
+ inclusive_tree_ = IsInclusiveTrie(kind);
+ tick_functions_ = !inclusive_tree_;
+ if (inclusive_tree_) {
BuildInclusiveFunctionTrie(root);
} else {
BuildExclusiveFunctionTrie(root);
@@ -1213,8 +1284,11 @@
void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie",
FLAG_trace_profiler);
- for (intptr_t i = 0; i < samples_->length(); i++) {
- ProcessedSample* sample = samples_->At(i);
+ ASSERT(!tick_functions_);
+ for (intptr_t sample_index = 0;
+ sample_index < samples_->length();
+ sample_index++) {
+ ProcessedSample* sample = samples_->At(sample_index);
// Tick the root.
ProfileFunctionTrieNode* current = root;
@@ -1226,20 +1300,14 @@
// Truncated tag.
if (sample->truncated()) {
current = AppendTruncatedTag(current);
- InclusiveTickTruncatedTag();
}
// Walk the sampled PCs.
- for (intptr_t j = sample->length() - 1; j >= 0; j--) {
- ASSERT(sample->At(j) != 0);
- current = ProcessFunctionPC(
- sample->At(j),
- sample->timestamp(),
- current,
- i,
- (j == 0),
- sample->first_frame_executing() || sample->IsAllocationSample(),
- true);
+ for (intptr_t frame_index = sample->length() - 1;
+ frame_index >= 0;
+ frame_index--) {
+ ASSERT(sample->At(frame_index) != 0);
+ current = ProcessFrame(current, sample_index, sample, frame_index);
}
}
}
@@ -1247,8 +1315,11 @@
void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie",
FLAG_trace_profiler);
- for (intptr_t i = 0; i < samples_->length(); i++) {
- ProcessedSample* sample = samples_->At(i);
+ ASSERT(tick_functions_);
+ for (intptr_t sample_index = 0;
+ sample_index < samples_->length();
+ sample_index++) {
+ ProcessedSample* sample = samples_->At(sample_index);
// Tick the root.
ProfileFunctionTrieNode* current = root;
@@ -1257,41 +1328,36 @@
// VM & User tags.
current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
+ ResetKind();
+
// Walk the sampled PCs.
- for (intptr_t j = 0; j < sample->length(); j++) {
- ASSERT(sample->At(j) != 0);
- current = ProcessFunctionPC(
- sample->At(j),
- sample->timestamp(),
- current,
- i,
- (j == 0),
- sample->first_frame_executing() || sample->IsAllocationSample(),
- false);
+ for (intptr_t frame_index = 0;
+ frame_index < sample->length();
+ frame_index++) {
+ ASSERT(sample->At(frame_index) != 0);
+ current = ProcessFrame(current, sample_index, sample, frame_index);
}
// Truncated tag.
if (sample->truncated()) {
current = AppendTruncatedTag(current);
+ InclusiveTickTruncatedTag();
}
}
}
- ProfileFunctionTrieNode* ProcessFunctionPC(
- uword pc,
- int64_t timestamp,
+ ProfileFunctionTrieNode* ProcessFrame(
ProfileFunctionTrieNode* current,
- intptr_t inclusive_serial,
- bool top_frame,
- bool top_frame_executing,
- bool inclusive_tree) {
- ProfileCode* profile_code = GetProfileCode(pc, timestamp);
+ intptr_t sample_index,
+ ProcessedSample* sample,
+ intptr_t frame_index) {
+ const uword pc = sample->At(frame_index);
+ ProfileCode* profile_code = GetProfileCode(pc,
+ sample->timestamp());
+ ProfileFunction* function = profile_code->function();
+ ASSERT(function != NULL);
+ const intptr_t code_index = profile_code->code_table_index();
ASSERT(profile_code != NULL);
- const char* code_name = profile_code->name();
- if (code_name == NULL) {
- code_name = "";
- }
- intptr_t code_index = profile_code->code_table_index();
const Code& code = Code::ZoneHandle(profile_code->code());
GrowableArray<Function*> inlined_functions;
if (!code.IsNull()) {
@@ -1300,42 +1366,63 @@
}
if (code.IsNull() || (inlined_functions.length() == 0)) {
// No inlined functions.
- ProfileFunction* function = profile_code->function();
- ASSERT(function != NULL);
- current = ProcessFunction(function,
- current,
- inclusive_serial,
- top_frame,
- top_frame_executing,
+ if (inclusive_tree_) {
+ current = AppendKind(code, current);
+ }
+ current = ProcessFunction(current,
+ sample_index,
+ sample,
+ frame_index,
+ function,
code_index);
+ if (!inclusive_tree_) {
+ current = AppendKind(code, current);
+ }
return current;
}
- if (inclusive_tree) {
+ ASSERT(code.is_optimized());
+
+ if (inclusive_tree_) {
for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) {
Function* inlined_function = inlined_functions[i];
ASSERT(inlined_function != NULL);
ASSERT(!inlined_function->IsNull());
- current = ProcessInlinedFunction(inlined_function,
- current,
- inclusive_serial,
- top_frame,
- top_frame_executing,
+ const bool inliner = i == (inlined_functions.length() - 1);
+ if (inliner) {
+ current = AppendKind(code, current);
+ }
+ current = ProcessInlinedFunction(current,
+ sample_index,
+ sample,
+ frame_index,
+ inlined_function,
code_index);
- top_frame = false;
+ if (inliner) {
+ current = AppendKind(kInlineStart, current);
+ }
}
+ current = AppendKind(kInlineFinish, current);
} else {
+ // Append the inlined children.
+ current = AppendKind(kInlineFinish, current);
for (intptr_t i = 0; i < inlined_functions.length(); i++) {
Function* inlined_function = inlined_functions[i];
ASSERT(inlined_function != NULL);
ASSERT(!inlined_function->IsNull());
- current = ProcessInlinedFunction(inlined_function,
- current,
- inclusive_serial,
- top_frame,
- top_frame_executing,
+ const bool inliner = i == (inlined_functions.length() - 1);
+ if (inliner) {
+ current = AppendKind(kInlineStart, current);
+ }
+ current = ProcessInlinedFunction(current,
+ sample_index,
+ sample,
+ frame_index + i,
+ inlined_function,
code_index);
- top_frame = false;
+ if (inliner) {
+ current = AppendKind(code, current);
+ }
}
}
@@ -1343,44 +1430,47 @@
}
ProfileFunctionTrieNode* ProcessInlinedFunction(
- Function* inlined_function,
ProfileFunctionTrieNode* current,
- intptr_t inclusive_serial,
- bool top_frame,
- bool top_frame_executing,
+ intptr_t sample_index,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ Function* inlined_function,
intptr_t code_index) {
ProfileFunctionTable* function_table = profile_->functions_;
ProfileFunction* function = function_table->LookupOrAdd(*inlined_function);
ASSERT(function != NULL);
- return ProcessFunction(function,
- current,
- inclusive_serial,
- top_frame,
- top_frame_executing,
+ return ProcessFunction(current,
+ sample_index,
+ sample,
+ frame_index,
+ function,
code_index);
}
- ProfileFunctionTrieNode* ProcessFunction(ProfileFunction* function,
- ProfileFunctionTrieNode* current,
- intptr_t inclusive_serial,
- bool top_frame,
- bool top_frame_executing,
+ bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) {
+ if (frame_index != 0) {
+ return true;
+ }
+ // Only tick the first frame's node, if we are executing OR
+ // vm tags have been emitted.
+ return IsExecutingFrame(sample, frame_index) || vm_tags_emitted();
+ }
+
+ ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current,
+ intptr_t sample_index,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ ProfileFunction* function,
intptr_t code_index) {
- const bool exclusive = top_frame && top_frame_executing;
if (tick_functions_) {
- function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
+ function->Tick(IsExecutingFrame(sample, frame_index), sample_index);
}
function->AddProfileCode(code_index);
current = current->GetChild(function->table_index());
- current->AddCodeObjectIndex(code_index);
- if (top_frame) {
- if (top_frame_executing || vm_tags_emitted()) {
- // Only tick if this function is using CPU time or VM tags are emitted.
- current->Tick();
- }
- } else {
+ if (ShouldTickNode(sample, frame_index)) {
current->Tick();
}
+ current->AddCodeObjectIndex(code_index);
return current;
}
@@ -1457,6 +1547,53 @@
return current;
}
+ uword ProfileInfoKindToVMTag(ProfileInfoKind kind) {
+ switch (kind) {
+ case kNone:
+ return VMTag::kNoneCodeTagId;
+ case kOptimized:
+ return VMTag::kOptimizedCodeTagId;
+ case kUnoptimized:
+ return VMTag::kUnoptimizedCodeTagId;
+ case kNative:
+ return VMTag::kNativeCodeTagId;
+ case kInlineStart:
+ return VMTag::kInlineStartCodeTagId;
+ case kInlineFinish:
+ return VMTag::kInlineEndCodeTagId;
+ default:
+ UNIMPLEMENTED();
+ return VMTag::kInvalidTagId;
+ }
+ }
+
+ ProfileCodeTrieNode* AppendKind(ProfileInfoKind kind,
+ ProfileCodeTrieNode* current) {
+ if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) {
+ // Only emit if debug tags are requested.
+ return current;
+ }
+ if (kind != info_kind_) {
+ info_kind_ = kind;
+ intptr_t tag_index = GetProfileCodeTagIndex(ProfileInfoKindToVMTag(kind));
+ ASSERT(tag_index >= 0);
+ current = current->GetChild(tag_index);
+ current->Tick();
+ }
+ return current;
+ }
+
+ ProfileCodeTrieNode* AppendKind(const Code& code,
+ ProfileCodeTrieNode* current) {
+ if (code.IsNull()) {
+ return AppendKind(kNone, current);
+ } else if (code.is_optimized()) {
+ return AppendKind(kOptimized, current);
+ } else {
+ return AppendKind(kUnoptimized, current);
+ }
+ }
+
ProfileCodeTrieNode* AppendVMTags(uword vm_tag,
ProfileCodeTrieNode* current) {
current = AppendVMTag(vm_tag, current);
@@ -1493,6 +1630,38 @@
}
// ProfileFunctionTrieNode
+ void ResetKind() {
+ info_kind_ = kNone;
+ }
+
+ ProfileFunctionTrieNode* AppendKind(ProfileInfoKind kind,
+ ProfileFunctionTrieNode* current) {
+ if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) {
+ // Only emit if debug tags are requested.
+ return current;
+ }
+ if (kind != info_kind_) {
+ info_kind_ = kind;
+ intptr_t tag_index =
+ GetProfileFunctionTagIndex(ProfileInfoKindToVMTag(kind));
+ ASSERT(tag_index >= 0);
+ current = current->GetChild(tag_index);
+ current->Tick();
+ }
+ return current;
+ }
+
+ ProfileFunctionTrieNode* AppendKind(const Code& code,
+ ProfileFunctionTrieNode* current) {
+ if (code.IsNull()) {
+ return AppendKind(kNone, current);
+ } else if (code.is_optimized()) {
+ return AppendKind(kOptimized, current);
+ } else {
+ return AppendKind(kUnoptimized, current);
+ }
+ }
+
ProfileFunctionTrieNode* AppendUserTag(uword user_tag,
ProfileFunctionTrieNode* current) {
intptr_t user_tag_index = GetProfileFunctionTagIndex(user_tag);
@@ -1514,7 +1683,7 @@
}
ProfileFunctionTrieNode* AppendVMTag(uword vm_tag,
- ProfileFunctionTrieNode* current) {
+ ProfileFunctionTrieNode* current) {
if (VMTag::IsNativeEntryTag(vm_tag)) {
// Insert a dummy kNativeTagId node.
intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId);
@@ -1776,17 +1945,24 @@
(tag_order_ == Profile::kVM);
}
+ bool TagsEnabled(intptr_t extra_tags_bits) const {
+ return (extra_tags_ & extra_tags_bits) != 0;
+ }
+
Isolate* isolate_;
Isolate* vm_isolate_;
SampleFilter* filter_;
Profile::TagOrder tag_order_;
+ intptr_t extra_tags_;
Profile* profile_;
DeoptimizedCodeSet* deoptimized_code_;
const Code& null_code_;
const Function& null_function_;
bool tick_functions_;
+ bool inclusive_tree_;
ProcessedSampleBuffer* samples_;
+ ProfileInfoKind info_kind_;
};
@@ -1807,8 +1983,10 @@
}
-void Profile::Build(SampleFilter* filter, TagOrder tag_order) {
- ProfileBuilder builder(isolate_, filter, tag_order, this);
+void Profile::Build(SampleFilter* filter,
+ TagOrder tag_order,
+ intptr_t extra_tags) {
+ ProfileBuilder builder(isolate_, filter, tag_order, extra_tags, this);
builder.Build();
}
@@ -1937,6 +2115,44 @@
}
+intptr_t ProfileTrieWalker::CurrentNodeTickCount() {
+ if (current_ == NULL) {
+ return -1;
+ }
+ return current_->count();
+}
+
+
+intptr_t ProfileTrieWalker::CurrentInclusiveTicks() {
+ if (current_ == NULL) {
+ return -1;
+ }
+ if (code_trie_) {
+ ProfileCode* code = profile_->GetCode(current_->table_index());
+ return code->inclusive_ticks();
+ } else {
+ ProfileFunction* func = profile_->GetFunction(current_->table_index());
+ return func->inclusive_ticks();
+ }
+ UNREACHABLE();
+}
+
+
+intptr_t ProfileTrieWalker::CurrentExclusiveTicks() {
+ if (current_ == NULL) {
+ return -1;
+ }
+ if (code_trie_) {
+ ProfileCode* code = profile_->GetCode(current_->table_index());
+ return code->exclusive_ticks();
+ } else {
+ ProfileFunction* func = profile_->GetFunction(current_->table_index());
+ return func->exclusive_ticks();
+ }
+ UNREACHABLE();
+}
+
+
bool ProfileTrieWalker::Down() {
if ((current_ == NULL) || (current_->NumChildren() == 0)) {
return false;
@@ -1964,9 +2180,16 @@
}
+intptr_t ProfileTrieWalker::SiblingCount() {
+ ASSERT(parent_ != NULL);
+ return parent_->NumChildren();
+}
+
+
void ProfilerService::PrintJSONImpl(Isolate* isolate,
JSONStream* stream,
Profile::TagOrder tag_order,
+ intptr_t extra_tags,
SampleFilter* filter) {
// Disable profile interrupts while processing the buffer.
Profiler::EndExecution(isolate);
@@ -1984,7 +2207,7 @@
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
- profile.Build(filter, tag_order);
+ profile.Build(filter, tag_order, extra_tags);
profile.PrintJSON(stream);
}
@@ -2006,10 +2229,11 @@
void ProfilerService::PrintJSON(JSONStream* stream,
- Profile::TagOrder tag_order) {
+ Profile::TagOrder tag_order,
+ intptr_t extra_tags) {
Isolate* isolate = Isolate::Current();
NoAllocationSampleFilter filter(isolate);
- PrintJSONImpl(isolate, stream, tag_order, &filter);
+ PrintJSONImpl(isolate, stream, tag_order, extra_tags, &filter);
}
@@ -2036,7 +2260,7 @@
const Class& cls) {
Isolate* isolate = Isolate::Current();
ClassAllocationSampleFilter filter(isolate, cls);
- PrintJSONImpl(isolate, stream, tag_order, &filter);
+ PrintJSONImpl(isolate, stream, tag_order, kNoExtraTags, &filter);
}
diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
index 7990b4d..7f0b9a3 100644
--- a/runtime/vm/profiler_service.h
+++ b/runtime/vm/profiler_service.h
@@ -300,7 +300,7 @@
explicit Profile(Isolate* isolate);
// Build a filtered model using |filter| with the specified |tag_order|.
- void Build(SampleFilter* filter, TagOrder tag_order);
+ void Build(SampleFilter* filter, TagOrder tag_order, intptr_t extra_tags = 0);
// After building:
int64_t min_time() const { return min_time_; }
@@ -349,6 +349,14 @@
void Reset(Profile::TrieKind trie_kind);
const char* CurrentName();
+ // Return the current node's peer's inclusive tick count.
+ intptr_t CurrentInclusiveTicks();
+ // Return the current node's peer's exclusive tick count.
+ intptr_t CurrentExclusiveTicks();
+ // Return the current node's tick count.
+ intptr_t CurrentNodeTickCount();
+ // Return the number siblings (including yourself).
+ intptr_t SiblingCount();
bool Down();
bool NextSibling();
@@ -363,8 +371,14 @@
class ProfilerService : public AllStatic {
public:
+ enum {
+ kNoExtraTags = 0,
+ kCodeTransitionTagsBit = (1 << 0),
+ };
+
static void PrintJSON(JSONStream* stream,
- Profile::TagOrder tag_order);
+ Profile::TagOrder tag_order,
+ intptr_t extra_tags);
static void PrintAllocationJSON(JSONStream* stream,
Profile::TagOrder tag_order,
@@ -376,6 +390,7 @@
static void PrintJSONImpl(Isolate* isolate,
JSONStream* stream,
Profile::TagOrder tag_order,
+ intptr_t extra_tags,
SampleFilter* filter);
};
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index b4b9080..965d6b3 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -314,6 +314,190 @@
}
+TEST_CASE(Profiler_CodeTicks) {
+ const char* kScript =
+ "class A {\n"
+ " var a;\n"
+ " var b;\n"
+ "}\n"
+ "class B {\n"
+ " static boo() {\n"
+ " return new A();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " B.boo();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+
+ const Class& class_a = Class::Handle(GetClass(root_library, "A"));
+ EXPECT(!class_a.IsNull());
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ // Turn on allocation tracing for A.
+ class_a.SetTraceAllocation(true);
+
+ // Allocate three times.
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have three allocation samples.
+ EXPECT_EQ(3, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ // Exclusive code: B.boo -> main.
+ walker.Reset(Profile::kExclusiveCode);
+ // Move down from the root.
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+
+ // Inclusive code: main -> B.boo.
+ walker.Reset(Profile::kInclusiveCode);
+ // Move down from the root.
+ EXPECT(walker.Down());
+ EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+ }
+}
+
+
+TEST_CASE(Profiler_FunctionTicks) {
+ const char* kScript =
+ "class A {\n"
+ " var a;\n"
+ " var b;\n"
+ "}\n"
+ "class B {\n"
+ " static boo() {\n"
+ " return new A();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " B.boo();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+
+ const Class& class_a = Class::Handle(GetClass(root_library, "A"));
+ EXPECT(!class_a.IsNull());
+
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ // Turn on allocation tracing for A.
+ class_a.SetTraceAllocation(true);
+
+ // Allocate three times.
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have three allocation samples.
+ EXPECT_EQ(3, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+
+ // Exclusive function: B.boo -> main.
+ walker.Reset(Profile::kExclusiveFunction);
+ // Move down from the root.
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+
+ // Inclusive function: main -> B.boo.
+ walker.Reset(Profile::kInclusiveFunction);
+ // Move down from the root.
+ EXPECT(walker.Down());
+ EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(3, walker.CurrentNodeTickCount());
+ EXPECT_EQ(3, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+ }
+}
+
+
TEST_CASE(Profiler_IntrinsicAllocation) {
const char* kScript = "double foo(double a, double b) => a + b;";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
@@ -731,4 +915,247 @@
}
}
+
+TEST_CASE(Profiler_FunctionInline) {
+ const char* kScript =
+ "class A {\n"
+ " var a;\n"
+ " var b;\n"
+ "}\n"
+ "class B {\n"
+ " static choo(bool alloc) {\n"
+ " if (alloc) return new A();\n"
+ " return alloc && alloc && !alloc;\n"
+ " }\n"
+ " static foo(bool alloc) {\n"
+ " choo(alloc);\n"
+ " }\n"
+ " static boo(bool alloc) {\n"
+ " for (var i = 0; i < 50000; i++) {\n"
+ " foo(alloc);\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " B.boo(false);\n"
+ "}\n"
+ "mainA() {\n"
+ " B.boo(true);\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+
+ const Class& class_a = Class::Handle(GetClass(root_library, "A"));
+ EXPECT(!class_a.IsNull());
+
+ // Compile "main".
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ // Compile "mainA".
+ result = Dart_Invoke(lib, NewString("mainA"), 0, NULL);
+ EXPECT_VALID(result);
+ // At this point B.boo should be optimized and inlined B.foo and B.choo.
+
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have no allocation samples.
+ EXPECT_EQ(0, profile.sample_count());
+ }
+
+ // Turn on allocation tracing for A.
+ class_a.SetTraceAllocation(true);
+
+ // Allocate 50,000 instances of A.
+ result = Dart_Invoke(lib, NewString("mainA"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter, Profile::kNoTags);
+ // We should have 50,000 allocation samples.
+ EXPECT_EQ(50000, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+ // We have two code objects: mainA and B.boo.
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+ // We have two code objects: mainA and B.boo.
+ walker.Reset(Profile::kInclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+
+ // Inline expansion should show us the complete call chain:
+ // mainA -> B.boo -> B.foo -> B.choo.
+ walker.Reset(Profile::kExclusiveFunction);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.choo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.foo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+
+ // Inline expansion should show us the complete call chain:
+ // mainA -> B.boo -> B.foo -> B.choo.
+ walker.Reset(Profile::kInclusiveFunction);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.foo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.choo", walker.CurrentName());
+ EXPECT_EQ(1, walker.SiblingCount());
+ EXPECT_EQ(50000, walker.CurrentNodeTickCount());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+ }
+
+ // Test code transition tags.
+ {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+ Profile profile(isolate);
+ AllocationFilter filter(isolate, class_a.id());
+ profile.Build(&filter,
+ Profile::kNoTags,
+ ProfilerService::kCodeTransitionTagsBit);
+ // We should have 50,000 allocation samples.
+ EXPECT_EQ(50000, profile.sample_count());
+ ProfileTrieWalker walker(&profile);
+ // We have two code objects: mainA and B.boo.
+ walker.Reset(Profile::kExclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
+ EXPECT(!walker.Down());
+ // We have two code objects: mainA and B.boo.
+ walker.Reset(Profile::kInclusiveCode);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(!walker.Down());
+
+ // Inline expansion should show us the complete call chain:
+ // mainA -> B.boo -> B.foo -> B.choo.
+ walker.Reset(Profile::kExclusiveFunction);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Inline End]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.choo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.foo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Inline Start]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
+ EXPECT(!walker.Down());
+
+ // Inline expansion should show us the complete call chain:
+ // mainA -> B.boo -> B.foo -> B.choo.
+ walker.Reset(Profile::kInclusiveFunction);
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Inline Start]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.foo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.choo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Inline End]", walker.CurrentName());
+ EXPECT(!walker.Down());
+ }
+}
+
} // namespace dart
+
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3313d17..fa91a14 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -369,6 +369,9 @@
void SetCanonical() {
UpdateTagBit<CanonicalObjectTag>(true);
}
+ void ClearCanonical() {
+ UpdateTagBit<CanonicalObjectTag>(false);
+ }
bool IsCreatedFromSnapshot() const {
return CreatedFromSnapshotTag::decode(ptr()->tags_);
}
@@ -581,6 +584,7 @@
friend class Scavenger;
friend class ScavengerVisitor;
friend class SizeExcludingClassVisitor; // GetClassId
+ friend class RetainingPathVisitor; // GetClassId
friend class SnapshotReader;
friend class SnapshotWriter;
friend class String;
@@ -828,6 +832,7 @@
RawAbstractType* type_;
RawInstance* value_; // Offset in words for instance and value for static.
RawArray* dependent_code_;
+ RawFunction* initializer_;
RawSmi* guarded_list_length_;
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->guarded_list_length_);
@@ -971,7 +976,8 @@
enum InlinedMetadataIndex {
kInlinedIntervalsIndex = 0,
kInlinedIdToFunctionIndex = 1,
- kInlinedMetadataSize = 2,
+ kInlinedCallerIdMapIndex = 2,
+ kInlinedMetadataSize = 3,
};
RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 057f8e9..cc193fa 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -21,6 +21,8 @@
((kind == Snapshot::kFull) ? \
reader->New##type(len) : type::New(len, HEAP_SPACE(kind)))
+#define OFFSET_OF_FROM(obj) \
+ obj.raw()->from() - reinterpret_cast<RawObject**>(obj.raw()->ptr())
RawClass* Class::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
@@ -67,9 +69,11 @@
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (cls.raw()->to() - cls.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(cls);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
- cls.StorePointer((cls.raw()->from() + i),
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
+ cls.StorePointer((cls.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
} else {
@@ -152,7 +156,7 @@
intptr_t num_flds = (unresolved_class.raw()->to() -
unresolved_class.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
unresolved_class.StorePointer((unresolved_class.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -205,7 +209,11 @@
// Allocate type object.
Type& type = Type::ZoneHandle(reader->zone(), NEW_OBJECT(Type));
- reader->AddBackRef(object_id, &type, kIsDeserialized);
+ bool is_canonical = RawObject::IsCanonical(tags);
+ bool defer_canonicalization = is_canonical &&
+ ((kind == Snapshot::kScript && RawObject::IsCreatedFromSnapshot(tags)) ||
+ kind == Snapshot::kMessage);
+ reader->AddBackRef(object_id, &type, kIsDeserialized, defer_canonicalization);
// Set all non object fields.
type.set_token_pos(reader->Read<int32_t>());
@@ -215,28 +223,15 @@
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (type.raw()->to() - type.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(type);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsInlinedObject, object_id, (i + from_offset));
type.StorePointer((type.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
- // If object needs to be a canonical object, Canonicalize it.
- // When reading a full snapshot we don't need to canonicalize the object
- // as it would already be a canonical object.
- // When reading a script snapshot we need to canonicalize only those object
- // references that are objects from the core library (loaded from a
- // full snapshot). Objects that are only in the script need not be
- // canonicalized as they are already canonical.
- // When reading a message snapshot we always have to canonicalize the object.
- if ((kind != Snapshot::kFull) && RawObject::IsCanonical(tags) &&
- (RawObject::IsCreatedFromSnapshot(tags) ||
- (kind == Snapshot::kMessage))) {
- type ^= type.Canonicalize();
- }
-
- // Set the object tags (This is done after 'Canonicalize', which
- // does not canonicalize a type already marked as canonical).
+ // Set the object tags.
type.set_tags(tags);
return type.raw();
@@ -289,8 +284,10 @@
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (type_ref.raw()->to() - type_ref.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(type_ref);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
type_ref.StorePointer((type_ref.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -341,8 +338,10 @@
// allocations may happen.
intptr_t num_flds = (type_parameter.raw()->to() -
type_parameter.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(type_parameter);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
type_parameter.StorePointer((type_parameter.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -396,8 +395,10 @@
// allocations may happen.
intptr_t num_flds = (bounded_type.raw()->to() -
bounded_type.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(bounded_type);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
bounded_type.StorePointer((bounded_type.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -451,40 +452,33 @@
TypeArguments& type_arguments = TypeArguments::ZoneHandle(
reader->zone(), NEW_OBJECT_WITH_LEN_SPACE(TypeArguments, len, kind));
- reader->AddBackRef(object_id, &type_arguments, kIsDeserialized);
+ bool is_canonical = RawObject::IsCanonical(tags);
+ bool defer_canonicalization = is_canonical &&
+ ((kind == Snapshot::kScript && RawObject::IsCreatedFromSnapshot(tags)) ||
+ kind == Snapshot::kMessage);
+ reader->AddBackRef(object_id,
+ &type_arguments,
+ kIsDeserialized,
+ defer_canonicalization);
// Set the instantiations field, which is only read from a full snapshot.
if (kind == Snapshot::kFull) {
- *(reader->ArrayHandle()) ^= reader->ReadObjectImpl();
+ *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
type_arguments.set_instantiations(*(reader->ArrayHandle()));
} else {
type_arguments.set_instantiations(Object::zero_array());
}
// Now set all the type fields.
+ intptr_t offset = type_arguments.TypeAddr(0) -
+ reinterpret_cast<RawAbstractType**>(type_arguments.raw()->ptr());
for (intptr_t i = 0; i < len; i++) {
- *reader->TypeHandle() ^= reader->ReadObjectImpl();
+ *reader->TypeHandle() ^=
+ reader->ReadObjectImpl(kAsInlinedObject, object_id, (i + offset));
type_arguments.SetTypeAt(i, *reader->TypeHandle());
}
- // If object needs to be a canonical object, Canonicalize it.
- // When reading a full snapshot we don't need to canonicalize the object
- // as it would already be a canonical object.
- // When reading a script snapshot we need to canonicalize only those object
- // references that are objects from the core library (loaded from a
- // full snapshot). Objects that are only in the script need not be
- // canonicalized as they are already canonical.
- // When reading a message snapshot we always have to canonicalize the object.
- if ((kind != Snapshot::kFull) && RawObject::IsCanonical(tags) &&
- (RawObject::IsCreatedFromSnapshot(tags) ||
- (kind == Snapshot::kMessage))) {
- type_arguments ^= type_arguments.Canonicalize();
- }
-
- // Set the object tags (This is done after setting the object fields
- // because 'SetTypeAt' has an assertion to check if the object is not
- // already canonical. Also, this is done after 'Canonicalize', which
- // does not canonicalize a type already marked as canonical).
+ // Set the object tags .
type_arguments.set_tags(tags);
return type_arguments.raw();
@@ -508,13 +502,13 @@
// Write out the instantiations field, but only in a full snapshot.
if (kind == Snapshot::kFull) {
- writer->WriteObjectImpl(ptr()->instantiations_);
+ writer->WriteObjectImpl(ptr()->instantiations_, kAsInlinedObject);
}
// Write out the individual types.
intptr_t len = Smi::Value(ptr()->length_);
for (intptr_t i = 0; i < len; i++) {
- writer->WriteObjectImpl(ptr()->types()[i]);
+ writer->WriteObjectImpl(ptr()->types()[i], kAsInlinedObject);
}
}
@@ -541,7 +535,7 @@
// allocations may happen.
intptr_t num_flds = (cls.raw()->to() - cls.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
cls.StorePointer((cls.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -592,7 +586,7 @@
// allocations may happen.
intptr_t num_flds = (data.raw()->to() - data.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- *(data.raw()->from() + i) = reader->ReadObjectRef();
+ *(data.raw()->from() + i) = reader->ReadObjectImpl(kAsReference);
}
return data.raw();
@@ -616,17 +610,17 @@
// Context scope.
// We don't write the context scope in the snapshot.
- writer->WriteObjectImpl(Object::null());
+ writer->WriteObjectImpl(Object::null(), kAsInlinedObject);
// Parent function.
- writer->WriteObjectImpl(ptr()->parent_function_);
+ writer->WriteObjectImpl(ptr()->parent_function_, kAsInlinedObject);
// Signature class.
- writer->WriteObjectImpl(ptr()->signature_class_);
+ writer->WriteObjectImpl(ptr()->signature_class_, kAsInlinedObject);
// Static closure/Closure allocation stub.
// We don't write the closure or allocation stub in the snapshot.
- writer->WriteObjectImpl(Object::null());
+ writer->WriteObjectImpl(Object::null(), kAsInlinedObject);
}
@@ -651,8 +645,10 @@
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (data.raw()->to() - data.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(data);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
data.StorePointer((data.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -715,8 +711,10 @@
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (func.raw()->to_snapshot() - func.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(func);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
func.StorePointer((func.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -787,8 +785,10 @@
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (field.raw()->to() - field.raw()->from());
+ intptr_t from_offset = OFFSET_OF_FROM(field);
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) =
+ reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
field.StorePointer((field.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -850,7 +850,7 @@
// allocations may happen.
intptr_t num_flds = (literal_token.raw()->to() - literal_token.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
literal_token.StorePointer((literal_token.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -910,10 +910,10 @@
}
// Read in the literal/identifier token array.
- *(reader->TokensHandle()) ^= reader->ReadObjectImpl();
+ *(reader->TokensHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
token_stream.SetTokenObjects(*(reader->TokensHandle()));
// Read in the private key in use by the token stream.
- *(reader->StringHandle()) ^= reader->ReadObjectImpl();
+ *(reader->StringHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
token_stream.SetPrivateKey(*(reader->StringHandle()));
return token_stream.raw();
@@ -942,9 +942,9 @@
writer->WriteBytes(stream->ptr()->data_, len);
// Write out the literal/identifier token array.
- writer->WriteObjectImpl(ptr()->token_objects_);
+ writer->WriteObjectImpl(ptr()->token_objects_, kAsInlinedObject);
// Write out the private key in use by the token stream.
- writer->WriteObjectImpl(ptr()->private_key_);
+ writer->WriteObjectImpl(ptr()->private_key_, kAsInlinedObject);
}
@@ -976,7 +976,7 @@
// allocations may happen.
intptr_t num_flds = (script.raw()->to_snapshot() - script.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
script.StorePointer((script.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1028,7 +1028,7 @@
if ((kind == Snapshot::kScript) && RawObject::IsCreatedFromSnapshot(tags)) {
ASSERT(kind != Snapshot::kFull);
// Lookup the object as it should already exist in the heap.
- *reader->StringHandle() ^= reader->ReadObjectImpl();
+ *reader->StringHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
library = Library::LookupLibrary(*reader->StringHandle());
} else {
// Allocate library object.
@@ -1063,7 +1063,7 @@
// allocations may happen.
intptr_t num_flds = (library.raw()->to() - library.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
library.StorePointer((library.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1092,7 +1092,7 @@
RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) {
ASSERT(kind != Snapshot::kFull);
// Write out library URL so that it can be looked up when reading.
- writer->WriteObjectImpl(ptr()->url_);
+ writer->WriteObjectImpl(ptr()->url_, kAsInlinedObject);
} else {
// Write out all non object fields.
writer->WriteClassIDValue(ptr()->index_);
@@ -1144,7 +1144,7 @@
// allocations may happen.
intptr_t num_flds = (prefix.raw()->to() - prefix.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
prefix.StorePointer((prefix.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1201,7 +1201,7 @@
// allocations may happen.
intptr_t num_flds = (ns.raw()->to() - ns.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
ns.StorePointer((ns.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1390,7 +1390,7 @@
result.set_tags(tags);
for (intptr_t i = 0; i < num_entries; i++) {
- (*reader->StringHandle()) ^= reader->ReadObjectRef();
+ (*reader->StringHandle()) ^= reader->ReadObjectImpl(kAsReference);
result.StorePointer(result.raw()->nameAddrAt(i),
reader->StringHandle()->raw());
}
@@ -1418,7 +1418,7 @@
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<int32_t>(ptr()->num_entries_);
for (intptr_t i = 0; i < ptr()->num_entries_; i++) {
- writer->WriteObjectImpl(ptr()->names()[i]);
+ writer->WriteObjectImpl(ptr()->names()[i], kAsInlinedObject);
}
if (ptr()->num_entries_ > 0) {
intptr_t len = ptr()->num_entries_ * sizeof(VarInfo);
@@ -1434,7 +1434,8 @@
Snapshot::Kind kind) {
ASSERT(reader->allow_code());
- *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(); // handled_types_data_
+ // handled_types_data.
+ *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
ExceptionHandlers& result =
ExceptionHandlers::ZoneHandle(reader->zone(),
@@ -1466,7 +1467,7 @@
writer->WriteInlinedObjectHeader(object_id);
writer->WriteIndexedObject(kExceptionHandlersCid);
writer->WriteTags(writer->GetObjectTags(this));
- writer->WriteObjectImpl(ptr()->handled_types_data_);
+ writer->WriteObjectImpl(ptr()->handled_types_data_, kAsInlinedObject);
if (ptr()->num_entries_ > 0) {
intptr_t len = ptr()->num_entries_ * sizeof(HandlerInfo);
@@ -1499,7 +1500,7 @@
// allocations may happen.
intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
context.StorePointer((context.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1630,7 +1631,7 @@
// allocations may happen.
intptr_t num_flds = (api_error.raw()->to() - api_error.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
api_error.StorePointer((api_error.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1681,7 +1682,7 @@
intptr_t num_flds =
(language_error.raw()->to() - language_error.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
language_error.StorePointer((language_error.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1728,7 +1729,7 @@
// allocations may happen.
intptr_t num_flds = (result.raw()->to() - result.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
result.StorePointer((result.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -1829,7 +1830,10 @@
// Check if the value could potentially fit in a Smi in our current
// architecture, if so return the object as a Smi.
if (Smi::IsValid(value)) {
- return Smi::New(static_cast<intptr_t>(value));
+ Smi& smi = Smi::ZoneHandle(reader->zone(),
+ Smi::New(static_cast<intptr_t>(value)));
+ reader->AddBackRef(object_id, &smi, kIsDeserialized);
+ return smi.raw();
}
// Create a Mint object or get canonical one if it is a canonical constant.
@@ -1894,7 +1898,7 @@
// allocations may happen.
intptr_t num_flds = (obj.raw()->to() - obj.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsInlinedObject);
obj.StorePointer(obj.raw()->from() + i,
reader->PassiveObjectHandle()->raw());
}
@@ -2059,7 +2063,9 @@
String& str_obj = String::Handle(reader->zone(), String::null());
if (kind == Snapshot::kFull) {
- ASSERT(reader->isolate()->no_safepoint_scope_depth() != 0);
+ // We currently only expect the Dart mutator to read snapshots.
+ reader->isolate()->AssertCurrentThreadIsMutator();
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
RawOneByteString* obj = reader->NewOneByteString(len);
str_obj = obj;
str_obj.set_tags(tags);
@@ -2258,7 +2264,7 @@
reader->AddBackRef(object_id, array, kIsDeserialized);
}
ASSERT(!RawObject::IsCanonical(tags));
- reader->ArrayReadFrom(*array, len, tags);
+ reader->ArrayReadFrom(object_id, *array, len, tags);
return array->raw();
}
@@ -2278,7 +2284,7 @@
NEW_OBJECT_WITH_LEN_SPACE(ImmutableArray, len, kind)));
reader->AddBackRef(object_id, array, kIsDeserialized);
}
- reader->ArrayReadFrom(*array, len, tags);
+ reader->ArrayReadFrom(object_id, *array, len, tags);
if (RawObject::IsCanonical(tags)) {
*array ^= array->CheckAndCanonicalize(NULL);
}
@@ -2328,7 +2334,7 @@
reader->AddBackRef(object_id, &array, kIsDeserialized);
intptr_t length = reader->ReadSmiValue();
array.SetLength(length);
- *(reader->ArrayHandle()) ^= reader->ReadObjectImpl();
+ *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
array.SetData(*(reader->ArrayHandle()));
*(reader->TypeArgumentsHandle()) = reader->ArrayHandle()->GetTypeArguments();
array.SetTypeArguments(*(reader->TypeArgumentsHandle()));
@@ -2352,7 +2358,7 @@
writer->Write<RawObject*>(ptr()->length_);
// Write out the Array object.
- writer->WriteObjectImpl(ptr()->data_);
+ writer->WriteObjectImpl(ptr()->data_, kAsInlinedObject);
}
@@ -2377,7 +2383,11 @@
map.set_tags(tags);
// Read the type arguments.
- *reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl();
+ intptr_t typeargs_offset =
+ reinterpret_cast<RawObject**>(&map.raw()->ptr()->type_arguments_) -
+ reinterpret_cast<RawObject**>(map.raw()->ptr());
+ *reader->TypeArgumentsHandle() ^=
+ reader->ReadObjectImpl(kAsInlinedObject, object_id, typeargs_offset);
map.SetTypeArguments(*reader->TypeArgumentsHandle());
// Read the number of key/value pairs.
@@ -2402,10 +2412,9 @@
map.SetHashMask(0); // Prefer sentinel 0 over null for better type feedback.
// Read the keys and values.
- bool is_canonical = RawObject::IsCanonical(tags);
+ bool as_reference = RawObject::IsCanonical(tags) ? false : true;
for (intptr_t i = 0; i < used_data; i++) {
- *reader->PassiveObjectHandle() =
- is_canonical ? reader->ReadObjectImpl() : reader->ReadObjectRef();
+ *reader->PassiveObjectHandle() = reader->ReadObjectImpl(as_reference);
data.SetAt(i, *reader->PassiveObjectHandle());
}
return map.raw();
@@ -2431,7 +2440,7 @@
writer->WriteTags(tags);
// Write out the type arguments.
- writer->WriteObjectImpl(ptr()->type_arguments_);
+ writer->WriteObjectImpl(ptr()->type_arguments_, kAsInlinedObject);
const intptr_t used_data = Smi::Value(ptr()->used_data_);
ASSERT((used_data & 1) == 0); // Keys + values, so must be even.
@@ -2441,7 +2450,7 @@
writer->Write<RawObject*>(Smi::New((used_data >> 1) - deleted_keys));
// Write out the keys and values.
- const bool is_canonical = RawObject::IsCanonical(tags);
+ const bool as_reference = RawObject::IsCanonical(tags) ? false : true;
RawArray* data_array = ptr()->data_;
RawObject** data_elements = data_array->ptr()->data();
ASSERT(used_data <= Smi::Value(data_array->ptr()->length_));
@@ -2457,13 +2466,8 @@
continue;
}
RawObject* value = data_elements[i + 1];
- if (is_canonical) {
- writer->WriteObjectImpl(key);
- writer->WriteObjectImpl(value);
- } else {
- writer->WriteObjectRef(key);
- writer->WriteObjectRef(value);
- }
+ writer->WriteObjectImpl(key, as_reference);
+ writer->WriteObjectImpl(value, as_reference);
}
DEBUG_ASSERT(deleted_keys_found == deleted_keys);
}
@@ -2677,8 +2681,9 @@
intptr_t cid = RawObject::ClassIdTag::decode(tags);
intptr_t length = reader->ReadSmiValue();
uint8_t* data = reinterpret_cast<uint8_t*>(reader->ReadRawPointerValue());
- const ExternalTypedData& obj = ExternalTypedData::Handle(
+ ExternalTypedData& obj = ExternalTypedData::Handle(
ExternalTypedData::New(cid, data, length));
+ reader->AddBackRef(object_id, &obj, kIsDeserialized);
void* peer = reinterpret_cast<void*>(reader->ReadRawPointerValue());
Dart_WeakPersistentHandleFinalizer callback =
reinterpret_cast<Dart_WeakPersistentHandleFinalizer>(
@@ -2916,7 +2921,7 @@
// allocations may happen.
intptr_t num_flds = (result.raw()->to() - result.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
result.StorePointer((result.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
@@ -2978,7 +2983,7 @@
// Read and Set all the other fields.
regex.StoreSmi(®ex.raw_ptr()->num_bracket_expressions_,
reader->ReadAsSmi());
- *reader->StringHandle() ^= reader->ReadObjectImpl();
+ *reader->StringHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
regex.set_pattern(*reader->StringHandle());
regex.StoreNonPointer(®ex.raw_ptr()->num_registers_,
reader->Read<int32_t>());
@@ -3005,7 +3010,7 @@
// Write out all the other fields.
writer->Write<RawObject*>(ptr()->num_bracket_expressions_);
- writer->WriteObjectImpl(ptr()->pattern_);
+ writer->WriteObjectImpl(ptr()->pattern_, kAsInlinedObject);
writer->Write<int32_t>(ptr()->num_registers_);
writer->Write<int8_t>(ptr()->type_flags_);
}
@@ -3031,7 +3036,7 @@
intptr_t num_flds = (weak_property.raw()->to() -
weak_property.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+ (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
weak_property.StorePointer((weak_property.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
diff --git a/runtime/vm/regexp_parser.cc b/runtime/vm/regexp_parser.cc
index 03abf5a..716afa4 100644
--- a/runtime/vm/regexp_parser.cc
+++ b/runtime/vm/regexp_parser.cc
@@ -217,6 +217,8 @@
bool RegExpParser::ParseFunction(ParsedFunction *parsed_function) {
+ VMTagScope tagScope(Thread::Current()->isolate(),
+ VMTag::kCompileParseRegExpTagId);
Zone* zone = parsed_function->zone();
JSRegExp& regexp = JSRegExp::Handle(parsed_function->function().regexp());
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 954f340..d9fe847 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -114,6 +114,47 @@
String& field_name = String::Handle();
if (is_getter) {
field_name ^= Field::NameFromGetter(function_name);
+
+ if (field_name.CharAt(0) == '#') {
+ if (!FLAG_lazy_dispatchers) {
+ return Function::null();
+ }
+
+ // Resolving a getter "get:#..." is a request to closurize an instance
+ // property of the receiver object. It can be of the form:
+ // - get:#id, which closurizes a method or getter id
+ // - get:#set:id, which closurizes a setter id
+ // - get:#operator, eg. get:#<<, which closurizes an operator method.
+ // If the property can be resolved, a method extractor function
+ // "get:#..." is created and injected into the receiver's class.
+ String& property_name = String::Handle(String::SubString(field_name, 1));
+ ASSERT(!Field::IsGetterName(property_name));
+
+ String& property_getter_name = String::Handle();
+ if (!Field::IsSetterName(property_name)) {
+ // If this is not a setter, we need to look for both the regular
+ // name and the getter name. (In the case of an operator, this
+ // code will also try to resolve for example get:<< and will fail,
+ // but that's harmless.)
+ property_getter_name = Field::GetterName(property_name);
+ }
+
+ Function& function = Function::Handle();
+ while (!cls.IsNull()) {
+ function = cls.LookupDynamicFunction(property_name);
+ if (!function.IsNull()) {
+ return CreateMethodExtractor(function_name, function);
+ }
+ if (!property_getter_name.IsNull()) {
+ function = cls.LookupDynamicFunction(property_getter_name);
+ if (!function.IsNull()) {
+ return CreateMethodExtractor(function_name, function);
+ }
+ }
+ cls = cls.SuperClass();
+ }
+ return Function::null();
+ }
}
// Now look for an instance function whose name matches function_name
diff --git a/runtime/vm/runtime_entry_arm.cc b/runtime/vm/runtime_entry_arm.cc
index e3aceb0..d355254 100644
--- a/runtime/vm/runtime_entry_arm.cc
+++ b/runtime/vm/runtime_entry_arm.cc
@@ -49,8 +49,7 @@
// informative error message.
__ LoadExternalLabel(R5, &label, kNotPatchable);
__ LoadImmediate(R4, argument_count);
- __ BranchLink(&Isolate::Current()->stub_code()->CallToRuntimeLabel(),
- kNotPatchable);
+ __ BranchLink(*StubCode::CallToRuntime_entry(), kNotPatchable);
}
}
diff --git a/runtime/vm/runtime_entry_arm64.cc b/runtime/vm/runtime_entry_arm64.cc
index a2edb95..38dbe43 100644
--- a/runtime/vm/runtime_entry_arm64.cc
+++ b/runtime/vm/runtime_entry_arm64.cc
@@ -49,15 +49,15 @@
__ mov(R26, SP);
__ ReserveAlignedFrameSpace(0);
__ mov(CSP, SP);
- __ BranchLink(&label, kNoPP);
+ __ BranchLink(&label);
__ mov(SP, R26);
__ mov(CSP, R25);
} else {
// Argument count is not checked here, but in the runtime entry for a more
// informative error message.
- __ LoadExternalLabel(R5, &label, kNotPatchable, PP);
- __ LoadImmediate(R4, argument_count, kNoPP);
- __ BranchLink(&Isolate::Current()->stub_code()->CallToRuntimeLabel(), PP);
+ __ LoadExternalLabel(R5, &label);
+ __ LoadImmediate(R4, argument_count);
+ __ BranchLink(*StubCode::CallToRuntime_entry());
}
}
diff --git a/runtime/vm/runtime_entry_ia32.cc b/runtime/vm/runtime_entry_ia32.cc
index 612b72b..33b0e5a 100644
--- a/runtime/vm/runtime_entry_ia32.cc
+++ b/runtime/vm/runtime_entry_ia32.cc
@@ -33,7 +33,7 @@
// informative error message.
__ movl(ECX, Immediate(GetEntryPoint()));
__ movl(EDX, Immediate(argument_count));
- __ call(&Isolate::Current()->stub_code()->CallToRuntimeLabel());
+ __ Call(*StubCode::CallToRuntime_entry());
}
}
diff --git a/runtime/vm/runtime_entry_mips.cc b/runtime/vm/runtime_entry_mips.cc
index 872a37c..03cfa1f 100644
--- a/runtime/vm/runtime_entry_mips.cc
+++ b/runtime/vm/runtime_entry_mips.cc
@@ -49,8 +49,7 @@
// informative error message.
__ LoadExternalLabel(S5, &label, kNotPatchable);
__ LoadImmediate(S4, argument_count);
- __ BranchLink(&Isolate::Current()->stub_code()->CallToRuntimeLabel(),
- kNotPatchable);
+ __ BranchLink(*StubCode::CallToRuntime_entry(), kNotPatchable);
}
}
diff --git a/runtime/vm/runtime_entry_x64.cc b/runtime/vm/runtime_entry_x64.cc
index 705eacd..df24e70 100644
--- a/runtime/vm/runtime_entry_x64.cc
+++ b/runtime/vm/runtime_entry_x64.cc
@@ -29,9 +29,9 @@
// Argument count is not checked here, but in the runtime entry for a more
// informative error message.
ExternalLabel label(GetEntryPoint());
- __ LoadExternalLabel(RBX, &label, kNotPatchable, PP);
+ __ LoadExternalLabel(RBX, &label, kNotPatchable);
__ movq(R10, Immediate(argument_count));
- __ Call(&Isolate::Current()->stub_code()->CallToRuntimeLabel(), PP);
+ __ Call(*StubCode::CallToRuntime_entry());
}
}
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index e68727a..6f4fd03 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -87,7 +87,7 @@
StreamInfo Service::gc_stream("GC");
StreamInfo Service::echo_stream("_Echo");
StreamInfo Service::graph_stream("_Graph");
-
+StreamInfo Service::logging_stream("_Logging");
static StreamInfo* streams_[] = {
&Service::isolate_stream,
@@ -95,6 +95,7 @@
&Service::gc_stream,
&Service::echo_stream,
&Service::graph_stream,
+ &Service::logging_stream,
};
@@ -508,7 +509,7 @@
HANDLESCOPE(isolate);
Instance& reply_port = Instance::Handle(isolate);
- String& seq = String::Handle(isolate);
+ Instance& seq = String::Handle(isolate);
String& method_name = String::Handle(isolate);
Array& param_keys = Array::Handle(isolate);
Array& param_values = Array::Handle(isolate);
@@ -519,7 +520,7 @@
param_values ^= msg.At(5);
ASSERT(!method_name.IsNull());
- ASSERT(!seq.IsNull());
+ ASSERT(seq.IsNull() || seq.IsString() || seq.IsNumber());
ASSERT(!param_keys.IsNull());
ASSERT(!param_values.IsNull());
ASSERT(param_keys.Length() == param_values.Length());
@@ -680,9 +681,22 @@
ASSERT(stream_id != NULL);
{
JSONObject jsobj(&js);
- jsobj.AddProperty("event", event);
- jsobj.AddProperty("streamId", stream_id);
+ jsobj.AddProperty("jsonrpc", "2.0");
+ jsobj.AddProperty("method", "streamNotify");
+ JSONObject params(&jsobj, "params");
+ params.AddProperty("streamId", stream_id);
+ params.AddProperty("event", event);
}
+ PostEvent(stream_id, event->KindAsCString(), &js);
+}
+
+
+void Service::PostEvent(const char* stream_id,
+ const char* kind,
+ JSONStream* event) {
+ ASSERT(stream_id != NULL);
+ ASSERT(kind != NULL);
+ ASSERT(event != NULL);
// Message is of the format [<stream id>, <json string>].
//
@@ -702,13 +716,12 @@
Dart_CObject json_cobj;
json_cobj.type = Dart_CObject_kString;
- json_cobj.value.as_string = const_cast<char*>(js.ToCString());
+ json_cobj.value.as_string = const_cast<char*>(event->ToCString());
list_values[1] = &json_cobj;
if (FLAG_trace_service) {
OS::Print(
- "vm-service: Pushing event of type %s to stream %s\n",
- event->KindAsCString(), stream_id);
+ "vm-service: Pushing event of type %s to stream %s\n", kind, stream_id);
}
Dart_PostCObject(ServiceIsolate::Port(), &list_cobj);
@@ -917,16 +930,21 @@
JSONStream js;
{
JSONObject jsobj(&js);
+ jsobj.AddProperty("jsonrpc", "2.0");
+ jsobj.AddProperty("method", "streamNotify");
{
- JSONObject event(&jsobj, "event");
- event.AddProperty("type", "Event");
- event.AddProperty("kind", "_Echo");
- event.AddProperty("isolate", isolate);
- if (text != NULL) {
- event.AddProperty("text", text);
+ JSONObject params(&jsobj, "params");
+ params.AddProperty("streamId", echo_stream.id());
+ {
+ JSONObject event(¶ms, "event");
+ event.AddProperty("type", "Event");
+ event.AddProperty("kind", "_Echo");
+ event.AddProperty("isolate", isolate);
+ if (text != NULL) {
+ event.AddProperty("text", text);
+ }
}
}
- jsobj.AddProperty("streamId", echo_stream.id());
}
const String& message = String::Handle(String::New(js.ToCString()));
uint8_t data[] = {0, 128, 255};
@@ -1505,10 +1523,9 @@
jsobj.AddProperty("length", length);
JSONArray elements(&jsobj, "elements");
Object& element = Object::Handle();
- Object& parent = Object::Handle();
- Smi& offset_from_parent = Smi::Handle();
- Class& parent_class = Class::Handle();
- Array& parent_field_map = Array::Handle();
+ Smi& slot_offset = Smi::Handle();
+ Class& element_class = Class::Handle();
+ Array& element_field_map = Array::Handle();
Field& field = Field::Handle();
limit = Utils::Minimum(limit, length);
for (intptr_t i = 0; i < limit; ++i) {
@@ -1518,22 +1535,23 @@
jselement.AddProperty("value", element);
// Interpret the word offset from parent as list index or instance field.
// TODO(koda): User-friendly interpretation for map entries.
- offset_from_parent ^= path.At((i * 2) + 1);
- int parent_i = i + 1;
- if (parent_i < limit) {
- parent = path.At(parent_i * 2);
- if (parent.IsArray()) {
- intptr_t element_index = offset_from_parent.Value() -
+ if (i > 0) {
+ slot_offset ^= path.At((i * 2) - 1);
+ if (element.IsArray()) {
+ intptr_t element_index = slot_offset.Value() -
(Array::element_offset(0) >> kWordSizeLog2);
jselement.AddProperty("parentListIndex", element_index);
- } else if (parent.IsInstance()) {
- parent_class ^= parent.clazz();
- parent_field_map = parent_class.OffsetToFieldMap();
- intptr_t offset = offset_from_parent.Value();
- if (offset > 0 && offset < parent_field_map.Length()) {
- field ^= parent_field_map.At(offset);
+ } else if (element.IsInstance()) {
+ element_class ^= element.clazz();
+ element_field_map = element_class.OffsetToFieldMap();
+ intptr_t offset = slot_offset.Value();
+ if (offset > 0 && offset < element_field_map.Length()) {
+ field ^= element_field_map.At(offset);
jselement.AddProperty("parentField", field);
}
+ } else {
+ intptr_t element_index = slot_offset.Value();
+ jselement.AddProperty("_parentWordOffset", element_index);
}
}
}
@@ -2328,6 +2346,7 @@
static const MethodParameter* get_cpu_profile_params[] = {
ISOLATE_PARAMETER,
new EnumParameter("tags", true, tags_enum_names),
+ new BoolParameter("_codeTransitionTags", false),
NULL,
};
@@ -2336,7 +2355,11 @@
static bool GetCpuProfile(Isolate* isolate, JSONStream* js) {
Profile::TagOrder tag_order =
EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
- ProfilerService::PrintJSON(js, tag_order);
+ intptr_t extra_tags = 0;
+ if (BoolParameter::Parse(js->LookupParam("_codeTransitionTags"))) {
+ extra_tags |= ProfilerService::kCodeTransitionTagsBit;
+ }
+ ProfilerService::PrintJSON(js, tag_order, extra_tags);
return true;
}
@@ -2460,17 +2483,22 @@
JSONStream js;
{
JSONObject jsobj(&js);
+ jsobj.AddProperty("jsonrpc", "2.0");
+ jsobj.AddProperty("method", "streamNotify");
{
- JSONObject event(&jsobj, "event");
- event.AddProperty("type", "Event");
- event.AddProperty("kind", "_Graph");
- event.AddProperty("isolate", isolate);
+ JSONObject params(&jsobj, "params");
+ params.AddProperty("streamId", graph_stream.id());
+ {
+ JSONObject event(¶ms, "event");
+ event.AddProperty("type", "Event");
+ event.AddProperty("kind", "_Graph");
+ event.AddProperty("isolate", isolate);
- event.AddProperty("chunkIndex", i);
- event.AddProperty("chunkCount", num_chunks);
- event.AddProperty("nodeCount", node_count);
+ event.AddProperty("chunkIndex", i);
+ event.AddProperty("chunkCount", num_chunks);
+ event.AddProperty("nodeCount", node_count);
+ }
}
- jsobj.AddProperty("streamId", graph_stream.id());
}
const String& message = String::Handle(String::New(js.ToCString()));
@@ -2512,6 +2540,30 @@
}
+void Service::SendLogEvent(Isolate* isolate,
+ int64_t sequence_number,
+ int64_t timestamp,
+ intptr_t level,
+ const String& name,
+ const String& message,
+ const Instance& zone,
+ const Object& error,
+ const Instance& stack_trace) {
+ ServiceEvent::LogRecord log_record;
+ log_record.sequence_number = sequence_number;
+ log_record.timestamp = timestamp;
+ log_record.level = level;
+ log_record.name = &name;
+ log_record.message = &message;
+ log_record.zone = &zone;
+ log_record.error = &error;
+ log_record.stack_trace = &stack_trace;
+ ServiceEvent event(isolate, ServiceEvent::kLogging);
+ event.set_log_record(log_record);
+ Service::HandleEvent(&event);
+}
+
+
class ContainsAddressVisitor : public FindObjectVisitor {
public:
ContainsAddressVisitor(Isolate* isolate, uword addr)
@@ -2540,6 +2592,29 @@
};
+static RawObject* GetObjectHelper(Isolate* isolate, uword addr) {
+ Object& object = Object::Handle(isolate);
+
+ {
+ NoSafepointScope no_safepoint;
+ ContainsAddressVisitor visitor(isolate, addr);
+ object = isolate->heap()->FindObject(&visitor);
+ }
+
+ if (!object.IsNull()) {
+ return object.raw();
+ }
+
+ {
+ NoSafepointScope no_safepoint;
+ ContainsAddressVisitor visitor(Dart::vm_isolate(), addr);
+ object = Dart::vm_isolate()->heap()->FindObject(&visitor);
+ }
+
+ return object.raw();
+}
+
+
static bool GetObjectByAddress(Isolate* isolate, JSONStream* js) {
const char* addr_str = js->LookupParam("address");
if (addr_str == NULL) {
@@ -2554,16 +2629,11 @@
return true;
}
bool ref = js->HasParam("ref") && js->ParamIs("ref", "true");
- Object& object = Object::Handle(isolate);
- {
- NoSafepointScope no_safepoint;
- ContainsAddressVisitor visitor(isolate, addr);
- object = isolate->heap()->FindObject(&visitor);
- }
- if (object.IsNull()) {
+ const Object& obj = Object::Handle(isolate, GetObjectHelper(isolate, addr));
+ if (obj.IsNull()) {
PrintSentinel(js, kFreeSentinel);
} else {
- object.PrintJSON(js, ref);
+ obj.PrintJSON(js, ref);
}
return true;
}
@@ -2706,7 +2776,7 @@
static bool GetVersion(Isolate* isolate, JSONStream* js) {
JSONObject jsobj(js);
jsobj.AddProperty("type", "Version");
- jsobj.AddProperty("major", static_cast<intptr_t>(1));
+ jsobj.AddProperty("major", static_cast<intptr_t>(2));
jsobj.AddProperty("minor", static_cast<intptr_t>(0));
jsobj.AddProperty("_privateMajor", static_cast<intptr_t>(0));
jsobj.AddProperty("_privateMinor", static_cast<intptr_t>(0));
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 9e253403..3b23f6d 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -108,12 +108,23 @@
const uint8_t* bytes,
intptr_t bytes_len);
+ static void SendLogEvent(Isolate* isolate,
+ int64_t sequence_number,
+ int64_t timestamp,
+ intptr_t level,
+ const String& name,
+ const String& message,
+ const Instance& zone,
+ const Object& error,
+ const Instance& stack_trace);
+
// Well-known streams.
static StreamInfo isolate_stream;
static StreamInfo debug_stream;
static StreamInfo gc_stream;
static StreamInfo echo_stream;
static StreamInfo graph_stream;
+ static StreamInfo logging_stream;
static bool ListenStream(const char* stream_id);
static void CancelStream(const char* stream_id);
@@ -137,6 +148,7 @@
static void SendEvent(const char* stream_id,
const char* event_type,
const Object& eventMessage);
+
// Does not take ownership of 'data'.
static void SendEventWithData(const char* stream_id,
const char* event_type,
@@ -144,6 +156,10 @@
const uint8_t* data,
intptr_t size);
+ static void PostEvent(const char* stream_id,
+ const char* kind,
+ JSONStream* event);
+
static EmbedderServiceHandler* isolate_service_handler_head_;
static EmbedderServiceHandler* root_service_handler_head_;
static Dart_ServiceStreamListenCallback stream_listen_callback_;
diff --git a/runtime/vm/service/message.dart b/runtime/vm/service/message.dart
index 631f0a7..f27a48b 100644
--- a/runtime/vm/service/message.dart
+++ b/runtime/vm/service/message.dart
@@ -52,12 +52,12 @@
}
Message.fromUri(this.client, Uri uri)
- : method = _methodNameFromUri(uri) {
+ : serial = '', method = _methodNameFromUri(uri) {
params.addAll(uri.queryParameters);
}
Message.forIsolate(this.client, Uri uri, RunningIsolate isolate)
- : method = _methodNameFromUri(uri) {
+ : serial = '', method = _methodNameFromUri(uri) {
params.addAll(uri.queryParameters);
params['isolateId'] = isolate.serviceId;
}
@@ -102,7 +102,7 @@
var request = new List(6)
..[0] = 0 // Make room for OOB message type.
..[1] = receivePort.sendPort
- ..[2] = serial.toString()
+ ..[2] = serial
..[3] = method
..[4] = keys
..[5] = values;
@@ -129,7 +129,7 @@
var request = new List(6)
..[0] = 0 // Make room for OOB message type.
..[1] = receivePort.sendPort
- ..[2] = serial.toString()
+ ..[2] = serial
..[3] = method
..[4] = keys
..[5] = values;
@@ -143,6 +143,7 @@
void setErrorResponse(String message) {
var response = {
+ 'jsonrpc': '2.0',
'id': serial,
'result' : {
'type': 'Error',
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 338cc8e..f05214d 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,10 +1,9 @@
-# Dart VM Service Protocol 1.0 (Draft 1)
+# Dart VM Service Protocol 2.0
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes _draft 1_ of _version 1.0_ of the Dart VM
-Service Protocol. This protocol is used to communicate with a running
-Dart Virtual Machine.
+This document describes of _version 2.0_ 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.
The VM will start a webserver which services protocol requests via WebSocket.
@@ -12,10 +11,9 @@
but this does not allow access to VM _events_ and is not documented
here.
-The Service Protocol is based on JSON-RPC 2.0
-(http://www.jsonrpc.org/specification). The Service Protocol has been
-extended to support pushing _events_ to the client, which is
-apparently outside the scope of the JSON-RPC specification.
+The Service Protocol uses [JSON-RPC 2.0][].
+
+[JSON-RPC 2.0]: http://www.jsonrpc.org/specification
**Table of Contents**
@@ -97,7 +95,7 @@
}
```
-Currently the _id_ property must be a string. The Service Protocol
+The _id_ property must be a string, number, or `null`. The Service Protocol
optionally accepts requests without the _jsonprc_ property.
An RPC response is a JSON object (http://json.org/). The response always specifies an
@@ -108,10 +106,10 @@
```
{
- "json-rpc": "2.0",
+ "jsonrpc": "2.0",
"result": {
"type": "Version",
- "major": 1,
+ "major": 2,
"minor": 0
}
"id": "1"
@@ -152,7 +150,7 @@
```
{
- "json-rpc": "2.0",
+ "jsonrpc": "2.0",
"error": {
"code": 103,
"message": "Stream already subscribed",
@@ -189,22 +187,27 @@
access to events pertaining to isolate births, deaths, and name changes. See [streamListen](#streamlisten)
for a list of the well-known stream ids and their associated events.
-Events arrive asynchronously over the WebSocket and always have the
-_streamId_ and _event_ properties:
+Stream events arrive asynchronously over the WebSocket. They're structured as
+JSON-RPC 2.0 requests with no _id_ property. The _method_ property will be
+_streamNotify_, and the _params_ will have _streamId_ and _event_ properties:
-```
+```json
{
- "event": {
- "type": "Event",
- "kind": "IsolateExit",
- "isolate": {
- "type": "@Isolate",
- "id": "isolates/33",
- "number": "51048743613",
- "name": "worker-isolate"
+ "json-rpc": "2.0",
+ "method": "streamNotify",
+ "params": {
+ "streamId": "Isolate",
+ "event": {
+ "type": "Event",
+ "kind": "IsolateExit",
+ "isolate": {
+ "type": "@Isolate",
+ "id": "isolates/33",
+ "number": "51048743613",
+ "name": "worker-isolate"
+ }
}
}
- "streamId": "Isolate"
}
```
@@ -212,6 +215,7 @@
Clients should be written to handle this gracefully.
+
## Types
By convention, every result and event provided by the Service Protocol
@@ -295,7 +299,7 @@
```
"result": {
"type": "Version",
- "major": 1,
+ "major": 2,
"minor": 0
}
```
diff --git a/runtime/vm/service/vmservice.dart b/runtime/vm/service/vmservice.dart
index e6889bb..2be15b6 100644
--- a/runtime/vm/service/vmservice.dart
+++ b/runtime/vm/service/vmservice.dart
@@ -156,6 +156,7 @@
String _encodeError(Message message, int code, {String details}) {
var response = {
+ 'jsonrpc': '2.0',
'id' : message.serial,
'error' : {
'code': code,
@@ -172,6 +173,7 @@
String _encodeResult(Message message, Map result) {
var response = {
+ 'jsonrpc': '2.0',
'id' : message.serial,
'result' : result,
};
@@ -259,7 +261,7 @@
// Make requests to each isolate.
for (var isolate in isolates) {
for (var request in perIsolateRequests) {
- var message = new Message.forIsolate(request, isolate);
+ var message = new Message.forIsolate(client, request, isolate);
// Decode the JSON and and insert it into the map. The map key
// is the request Uri.
var response = JSON.decode(await isolate.route(message));
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index a53ace2..d704091 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -89,6 +89,8 @@
return "Inspect";
case kEmbedder:
return embedder_kind();
+ case kLogging:
+ return "_Logging";
case kDebuggerSettingsUpdate:
return "_DebuggerSettingsUpdate";
case kIllegal:
@@ -126,6 +128,9 @@
case kEmbedder:
return embedder_stream_id_;
+ case kLogging:
+ return Service::logging_stream.id();
+
default:
UNREACHABLE();
return NULL;
@@ -135,9 +140,7 @@
void ServiceEvent::PrintJSON(JSONStream* js) const {
JSONObject jsobj(js);
- jsobj.AddProperty("type", "Event");
- jsobj.AddProperty("kind", KindAsCString());
- jsobj.AddProperty("isolate", isolate());
+ PrintJSONHeader(&jsobj);
if (kind() == kPauseBreakpoint) {
JSONArray jsarr(&jsobj, "pauseBreakpoints");
// TODO(rmacnak): If we are paused at more than one breakpoint,
@@ -163,7 +166,7 @@
if (exception() != NULL) {
jsobj.AddProperty("exception", *(exception()));
}
- if (async_continuation() != NULL) {
+ if (async_continuation() != NULL && !async_continuation()->IsNull()) {
jsobj.AddProperty("_asyncContinuation", *(async_continuation()));
}
if (inspectee() != NULL) {
@@ -177,6 +180,25 @@
if (bytes() != NULL) {
jsobj.AddPropertyBase64("bytes", bytes(), bytes_length());
}
+ if (kind() == kLogging) {
+ JSONObject logRecord(&jsobj, "logRecord");
+ logRecord.AddProperty64("sequenceNumber", log_record_.sequence_number);
+ logRecord.AddPropertyTimeMillis("time", log_record_.timestamp);
+ logRecord.AddProperty64("level", log_record_.level);
+ logRecord.AddProperty("loggerName", *(log_record_.name));
+ logRecord.AddProperty("message", *(log_record_.message));
+ logRecord.AddProperty("zone", *(log_record_.zone));
+ logRecord.AddProperty("error", *(log_record_.error));
+ logRecord.AddProperty("stackTrace", *(log_record_.stack_trace));
+ }
+}
+
+
+void ServiceEvent::PrintJSONHeader(JSONObject* jsobj) const {
+ ASSERT(jsobj != NULL);
+ jsobj->AddProperty("type", "Event");
+ jsobj->AddProperty("kind", KindAsCString());
+ jsobj->AddProperty("isolate", isolate());
}
} // namespace dart
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index 8f81da5..6ebc211 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -34,9 +34,22 @@
kEmbedder,
+ kLogging,
+
kIllegal,
};
+ struct LogRecord {
+ int64_t sequence_number;
+ int64_t timestamp;
+ intptr_t level;
+ const String* name;
+ const String* message;
+ const Instance* zone;
+ const Object* error;
+ const Instance* stack_trace;
+ };
+
ServiceEvent(Isolate* isolate, EventKind event_kind)
: isolate_(isolate),
kind_(event_kind),
@@ -138,8 +151,14 @@
bytes_length_ = bytes_length;
}
+ void set_log_record(const LogRecord& log_record) {
+ log_record_ = log_record;
+ }
+
void PrintJSON(JSONStream* js) const;
+ void PrintJSONHeader(JSONObject* jsobj) const;
+
private:
Isolate* isolate_;
EventKind kind_;
@@ -153,6 +172,7 @@
const Heap::GCStats* gc_stats_;
const uint8_t* bytes_;
intptr_t bytes_length_;
+ LogRecord log_record_;
};
} // namespace dart
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 8c16909..310305a 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -530,15 +530,15 @@
Array& service_msg = Array::Handle();
- service_msg = Eval(lib, "[0, port, '0', 'alpha', [], []]");
+ service_msg = Eval(lib, "[0, port, '\"', 'alpha', [], []]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ("{\"json-rpc\":\"2.0\", \"result\":alpha, \"id\":\"0\"}",
+ EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"\\\"\"}",
handler.msg());
- service_msg = Eval(lib, "[0, port, '0', 'beta', [], []]");
+ service_msg = Eval(lib, "[0, port, 1, 'beta', [], []]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ("{\"json-rpc\":\"2.0\", \"result\":beta, \"id\":\"0\"}",
+ EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":beta,\"id\":1}",
handler.msg());
}
@@ -573,12 +573,12 @@
service_msg = Eval(lib, "[0, port, '0', 'alpha', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ("{\"json-rpc\":\"2.0\", \"result\":alpha, \"id\":\"0\"}",
+ EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"0\"}",
handler.msg());
service_msg = Eval(lib, "[0, port, '0', 'beta', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ("{\"json-rpc\":\"2.0\", \"result\":beta, \"id\":\"0\"}",
+ EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":beta,\"id\":\"0\"}",
handler.msg());
}
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 37d4f43..45ae49a 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3859,7 +3859,7 @@
// Prepare for unwinding frames by destroying all the stack resources
// in the previous C++ frames.
Isolate* isolate = thread->isolate();
- StackResource::Unwind(isolate);
+ StackResource::Unwind(thread);
// Unwind the C++ stack and continue simulation in the target frame.
set_register(PC, static_cast<int32_t>(pc));
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index c3dadd2..9663fdc 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3519,7 +3519,7 @@
// Prepare for unwinding frames by destroying all the stack resources
// in the previous C++ frames.
Isolate* isolate = thread->isolate();
- StackResource::Unwind(isolate);
+ StackResource::Unwind(thread);
// Unwind the C++ stack and continue simulation in the target frame.
set_pc(static_cast<int64_t>(pc));
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index cd20f68..fdcdcf2 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -2467,7 +2467,7 @@
// Prepare for unwinding frames by destroying all the stack resources
// in the previous C++ frames.
Isolate* isolate = thread->isolate();
- StackResource::Unwind(isolate);
+ StackResource::Unwind(thread);
// Unwind the C++ stack and continue simulation in the target frame.
set_pc(static_cast<int32_t>(pc));
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index a566bc9..98ae976 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -20,6 +20,11 @@
#include "vm/verified_memory.h"
#include "vm/version.h"
+// We currently only expect the Dart mutator to read snapshots.
+#define ASSERT_NO_SAFEPOINT_SCOPE() \
+ isolate()->AssertCurrentThreadIsMutator(); \
+ ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0)
+
namespace dart {
static const int kNumVmIsolateSnapshotReferences = 32 * KB;
@@ -201,13 +206,15 @@
// Setup for long jump in case there is an exception while reading.
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- PassiveObject& obj = PassiveObject::Handle(isolate(), ReadObjectImpl());
+ PassiveObject& obj =
+ PassiveObject::Handle(isolate(), ReadObjectImpl(kAsInlinedObject));
for (intptr_t i = 0; i < backward_references_->length(); i++) {
if (!(*backward_references_)[i].is_deserialized()) {
- ReadObjectImpl();
+ ReadObjectImpl(kAsInlinedObject);
(*backward_references_)[i].set_state(kIsDeserialized);
}
}
+ ProcessDeferredCanonicalizations();
return obj.raw();
} else {
// An error occurred while reading, return the error object.
@@ -230,12 +237,12 @@
Class& cls = Class::ZoneHandle(zone(), Class::null());
AddBackRef(object_id, &cls, kIsDeserialized);
// Read the library/class information and lookup the class.
- str_ ^= ReadObjectImpl(class_header);
+ str_ ^= ReadObjectImpl(class_header, kAsInlinedObject, kInvalidPatchIndex, 0);
library_ = Library::LookupLibrary(str_);
if (library_.IsNull() || !library_.Loaded()) {
SetReadException("Invalid object found in message.");
}
- str_ ^= ReadObjectImpl();
+ str_ ^= ReadObjectImpl(kAsInlinedObject);
cls = library_.LookupClass(str_);
if (cls.IsNull()) {
SetReadException("Invalid object found in message.");
@@ -256,14 +263,14 @@
AddBackRef(object_id, &obj, kIsDeserialized);
// Read the library/class/function information and lookup the function.
- str_ ^= ReadObjectImpl();
+ str_ ^= ReadObjectImpl(kAsInlinedObject);
library_ = Library::LookupLibrary(str_);
if (library_.IsNull() || !library_.Loaded()) {
SetReadException("Invalid Library object found in message.");
}
- str_ ^= ReadObjectImpl();
+ str_ ^= ReadObjectImpl(kAsInlinedObject);
if (str_.Equals(Symbols::TopLevel())) {
- str_ ^= ReadObjectImpl();
+ str_ ^= ReadObjectImpl(kAsInlinedObject);
func = library_.LookupFunctionAllowPrivate(str_);
} else {
cls_ = library_.LookupClassAllowPrivate(str_);
@@ -272,7 +279,7 @@
SetReadException("Invalid Class object found in message.");
}
cls_.EnsureIsFinalized(isolate());
- str_ ^= ReadObjectImpl();
+ str_ ^= ReadObjectImpl(kAsInlinedObject);
func = cls_.LookupFunctionAllowPrivate(str_);
}
if (func.IsNull()) {
@@ -287,16 +294,6 @@
}
-RawObject* SnapshotReader::ReadObjectImpl() {
- int64_t value = Read<int64_t>();
- if ((value & kSmiTagMask) == kSmiTag) {
- return NewInteger(value);
- }
- ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
- return ReadObjectImpl(static_cast<intptr_t>(value));
-}
-
-
intptr_t SnapshotReader::NextAvailableObjectId() const {
return backward_references_->length() +
kMaxPredefinedObjectIds + max_vm_isolate_object_id_;
@@ -326,45 +323,63 @@
}
-RawObject* SnapshotReader::ReadObjectImpl(intptr_t header_value) {
+RawObject* SnapshotReader::ReadObjectImpl(bool as_reference,
+ intptr_t patch_object_id,
+ intptr_t patch_offset) {
+ int64_t header_value = Read<int64_t>();
+ if ((header_value & kSmiTagMask) == kSmiTag) {
+ return NewInteger(header_value);
+ }
+ ASSERT((header_value <= kIntptrMax) && (header_value >= kIntptrMin));
+ return ReadObjectImpl(static_cast<intptr_t>(header_value),
+ as_reference,
+ patch_object_id,
+ patch_offset);
+}
+
+
+RawObject* SnapshotReader::ReadObjectImpl(intptr_t header_value,
+ bool as_reference,
+ intptr_t patch_object_id,
+ intptr_t patch_offset) {
if (IsVMIsolateObject(header_value)) {
return ReadVMIsolateObject(header_value);
} else {
if (SerializedHeaderTag::decode(header_value) == kObjectId) {
- return ReadIndexedObject(SerializedHeaderData::decode(header_value));
+ return ReadIndexedObject(SerializedHeaderData::decode(header_value),
+ patch_object_id,
+ patch_offset);
}
ASSERT(SerializedHeaderTag::decode(header_value) == kInlined);
intptr_t object_id = SerializedHeaderData::decode(header_value);
if (object_id == kOmittedObjectId) {
object_id = NextAvailableObjectId();
}
- return ReadInlinedObject(object_id);
+
+ // Read the class header information.
+ intptr_t class_header = Read<int32_t>();
+ intptr_t tags = ReadTags();
+ if (as_reference && !RawObject::IsCanonical(tags)) {
+ return ReadObjectRef(object_id,
+ class_header,
+ tags,
+ patch_object_id,
+ patch_offset);
+ }
+ return ReadInlinedObject(object_id,
+ class_header,
+ tags,
+ patch_object_id,
+ patch_offset);
}
}
-RawObject* SnapshotReader::ReadObjectRef() {
- int64_t header_value = Read<int64_t>();
- if ((header_value & kSmiTagMask) == kSmiTag) {
- return NewInteger(header_value);
- }
- ASSERT((header_value <= kIntptrMax) && (header_value >= kIntptrMin));
- intptr_t value = static_cast<intptr_t>(header_value);
- if (IsVMIsolateObject(value)) {
- return ReadVMIsolateObject(value);
- } else if (SerializedHeaderTag::decode(value) == kObjectId) {
- return ReadIndexedObject(SerializedHeaderData::decode(value));
- }
- ASSERT(SerializedHeaderTag::decode(value) == kInlined);
- intptr_t object_id = SerializedHeaderData::decode(value);
- if (object_id == kOmittedObjectId) {
- object_id = NextAvailableObjectId();
- }
- ASSERT(GetBackRef(object_id) == NULL);
-
- // Read the class header information and lookup the class.
- intptr_t class_header = Read<int32_t>();
-
+RawObject* SnapshotReader::ReadObjectRef(intptr_t object_id,
+ intptr_t class_header,
+ intptr_t tags,
+ intptr_t patch_object_id,
+ intptr_t patch_offset) {
// Since we are only reading an object reference, If it is an instance kind
// then we only need to figure out the class of the object and allocate an
// instance of it. The individual fields will be read later.
@@ -373,7 +388,7 @@
Instance& result = Instance::ZoneHandle(zone(), Instance::null());
AddBackRef(object_id, &result, kIsNotDeserialized);
- cls_ ^= ReadObjectImpl(); // Read class information.
+ cls_ ^= ReadObjectImpl(kAsInlinedObject); // Read class information.
ASSERT(!cls_.IsNull());
intptr_t instance_size = cls_.instance_size();
ASSERT(instance_size > 0);
@@ -387,7 +402,6 @@
// We skip the tags that have been written as the implicit static
// closure is going to be created in this isolate or the canonical
// version already created in the isolate will be used.
- ReadTags();
return ReadStaticImplicitClosure(object_id, class_header);
}
ASSERT((class_header & kSmiTagMask) != kSmiTag);
@@ -419,7 +433,6 @@
}
// For all other internal VM classes we read the object inline.
- intptr_t tags = ReadTags();
switch (class_id) {
#define SNAPSHOT_READ(clazz) \
case clazz::kClassId: { \
@@ -455,14 +468,131 @@
}
+RawObject* SnapshotReader::ReadInlinedObject(intptr_t object_id,
+ intptr_t class_header,
+ intptr_t tags,
+ intptr_t patch_object_id,
+ intptr_t patch_offset) {
+ // Lookup the class based on the class header information.
+ intptr_t header_id = SerializedHeaderData::decode(class_header);
+ if (header_id == kInstanceObjectId) {
+ // Object is regular dart instance.
+ Instance* result = reinterpret_cast<Instance*>(GetBackRef(object_id));
+ intptr_t instance_size = 0;
+ if (result == NULL) {
+ result = &(Instance::ZoneHandle(zone(), Instance::null()));
+ AddBackRef(object_id, result, kIsDeserialized);
+ cls_ ^= ReadObjectImpl(kAsInlinedObject);
+ ASSERT(!cls_.IsNull());
+ instance_size = cls_.instance_size();
+ ASSERT(instance_size > 0);
+ // Allocate the instance and read in all the fields for the object.
+ if (kind_ == Snapshot::kFull) {
+ *result ^= AllocateUninitialized(cls_.id(), instance_size);
+ } else {
+ *result ^= Object::Allocate(cls_.id(),
+ instance_size,
+ HEAP_SPACE(kind_));
+ }
+ } else {
+ cls_ ^= ReadObjectImpl(kAsInlinedObject);
+ ASSERT(!cls_.IsNull());
+ instance_size = cls_.instance_size();
+ }
+ intptr_t next_field_offset = cls_.next_field_offset();
+ intptr_t type_argument_field_offset = cls_.type_arguments_field_offset();
+ ASSERT(next_field_offset > 0);
+ // Instance::NextFieldOffset() returns the offset of the first field in
+ // a Dart object.
+ bool as_reference = RawObject::IsCanonical(tags) ? false : true;
+ intptr_t offset = Instance::NextFieldOffset();
+ intptr_t result_cid = result->GetClassId();
+ while (offset < next_field_offset) {
+ pobj_ = ReadObjectImpl(as_reference);
+ result->SetFieldAtOffset(offset, pobj_);
+ if ((offset != type_argument_field_offset) &&
+ (kind_ == Snapshot::kMessage)) {
+ // TODO(fschneider): Consider hoisting these lookups out of the loop.
+ // This would involve creating a handle, since cls_ can't be reused
+ // across the call to ReadObjectImpl.
+ cls_ = isolate()->class_table()->At(result_cid);
+ array_ = cls_.OffsetToFieldMap();
+ field_ ^= array_.At(offset >> kWordSizeLog2);
+ ASSERT(!field_.IsNull());
+ ASSERT(field_.Offset() == offset);
+ obj_ = pobj_.raw();
+ field_.RecordStore(obj_);
+ }
+ // TODO(fschneider): Verify the guarded cid and length for other kinds of
+ // snapshot (kFull, kScript) with asserts.
+ offset += kWordSize;
+ }
+ if (kind_ == Snapshot::kFull) {
+ // We create an uninitialized object in the case of full snapshots, so
+ // we need to initialize any remaining padding area with the Null object.
+ while (offset < instance_size) {
+ result->SetFieldAtOffset(offset, Object::null_object());
+ offset += kWordSize;
+ }
+ result->SetCreatedFromSnapshot();
+ } else if (RawObject::IsCanonical(tags)) {
+ *result = result->CheckAndCanonicalize(NULL);
+ ASSERT(!result->IsNull());
+ }
+ return result->raw();
+ } else if (header_id == kStaticImplicitClosureObjectId) {
+ // We do not use the tags as the implicit static closure
+ // is going to be created in this isolate or the canonical
+ // version already created in the isolate will be used.
+ return ReadStaticImplicitClosure(object_id, class_header);
+ }
+ ASSERT((class_header & kSmiTagMask) != kSmiTag);
+ intptr_t class_id = LookupInternalClass(class_header);
+ switch (class_id) {
+#define SNAPSHOT_READ(clazz) \
+ case clazz::kClassId: { \
+ pobj_ = clazz::ReadFrom(this, object_id, tags, kind_); \
+ break; \
+ }
+ CLASS_LIST_NO_OBJECT(SNAPSHOT_READ)
+#undef SNAPSHOT_READ
+#define SNAPSHOT_READ(clazz) \
+ case kTypedData##clazz##Cid: \
+
+ CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
+ tags = RawObject::ClassIdTag::update(class_id, tags);
+ pobj_ = TypedData::ReadFrom(this, object_id, tags, kind_);
+ break;
+ }
+#undef SNAPSHOT_READ
+#define SNAPSHOT_READ(clazz) \
+ case kExternalTypedData##clazz##Cid: \
+
+ CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
+ tags = RawObject::ClassIdTag::update(class_id, tags);
+ pobj_ = ExternalTypedData::ReadFrom(this, object_id, tags, kind_);
+ break;
+ }
+#undef SNAPSHOT_READ
+ default: UNREACHABLE(); break;
+ }
+ if (kind_ == Snapshot::kFull) {
+ pobj_.SetCreatedFromSnapshot();
+ }
+ AddPatchRecord(object_id, patch_object_id, patch_offset);
+ return pobj_.raw();
+}
+
+
void SnapshotReader::AddBackRef(intptr_t id,
Object* obj,
- DeserializeState state) {
+ DeserializeState state,
+ bool defer_canonicalization) {
intptr_t index = (id - kMaxPredefinedObjectIds);
ASSERT(index >= max_vm_isolate_object_id_);
index -= max_vm_isolate_object_id_;
ASSERT(index == backward_references_->length());
- BackRefNode node(obj, state);
+ BackRefNode node(obj, state, defer_canonicalization);
backward_references_->Add(node);
}
@@ -518,11 +648,11 @@
// Read in all the objects stored in the object store.
intptr_t num_flds = (object_store->to() - object_store->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- *(object_store->from() + i) = ReadObjectImpl();
+ *(object_store->from() + i) = ReadObjectImpl(kAsInlinedObject);
}
for (intptr_t i = 0; i < backward_references_->length(); i++) {
if (!(*backward_references_)[i].is_deserialized()) {
- ReadObjectImpl();
+ ReadObjectImpl(kAsInlinedObject);
(*backward_references_)[i].set_state(kIsDeserialized);
}
}
@@ -609,7 +739,7 @@
#define ALLOC_NEW_OBJECT_WITH_LEN(type, length) \
ASSERT(kind_ == Snapshot::kFull); \
- ASSERT(isolate()->no_safepoint_scope_depth() != 0); \
+ ASSERT_NO_SAFEPOINT_SCOPE(); \
Raw##type* obj = reinterpret_cast<Raw##type*>( \
AllocateUninitialized(k##type##Cid, type::InstanceSize(length))); \
obj->StoreSmi(&(obj->ptr()->length_), Smi::New(length)); \
@@ -643,7 +773,7 @@
RawTokenStream* SnapshotReader::NewTokenStream(intptr_t len) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
stream_ = reinterpret_cast<RawTokenStream*>(
AllocateUninitialized(kTokenStreamCid, TokenStream::InstanceSize()));
uint8_t* array = const_cast<uint8_t*>(CurrentBufferAddress());
@@ -661,7 +791,7 @@
RawContext* SnapshotReader::NewContext(intptr_t num_variables) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawContext* obj = reinterpret_cast<RawContext*>(
AllocateUninitialized(kContextCid, Context::InstanceSize(num_variables)));
obj->ptr()->num_variables_ = num_variables;
@@ -671,7 +801,7 @@
RawClass* SnapshotReader::NewClass(intptr_t class_id) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
if (class_id < kNumPredefinedCids) {
ASSERT((class_id >= kInstanceCid) &&
(class_id <= kNullCid));
@@ -690,7 +820,7 @@
RawInstance* SnapshotReader::NewInstance() {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawInstance* obj = reinterpret_cast<RawInstance*>(
AllocateUninitialized(kObjectCid, Instance::InstanceSize()));
return obj;
@@ -699,7 +829,7 @@
RawMint* SnapshotReader::NewMint(int64_t value) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawMint* obj = reinterpret_cast<RawMint*>(
AllocateUninitialized(kMintCid, Mint::InstanceSize()));
obj->ptr()->value_ = value;
@@ -709,7 +839,7 @@
RawDouble* SnapshotReader::NewDouble(double value) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawDouble* obj = reinterpret_cast<RawDouble*>(
AllocateUninitialized(kDoubleCid, Double::InstanceSize()));
obj->ptr()->value_ = value;
@@ -719,7 +849,7 @@
RawTypedData* SnapshotReader::NewTypedData(intptr_t class_id, intptr_t len) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
const intptr_t lengthInBytes = len * TypedData::ElementSizeInBytes(class_id);
RawTypedData* obj = reinterpret_cast<RawTypedData*>(
AllocateUninitialized(class_id, TypedData::InstanceSize(lengthInBytes)));
@@ -730,7 +860,7 @@
#define ALLOC_NEW_OBJECT(type) \
ASSERT(kind_ == Snapshot::kFull); \
- ASSERT(isolate()->no_safepoint_scope_depth() != 0); \
+ ASSERT_NO_SAFEPOINT_SCOPE(); \
return reinterpret_cast<Raw##type*>( \
AllocateUninitialized(k##type##Cid, type::InstanceSize())); \
@@ -828,7 +958,7 @@
RawFloat32x4* SnapshotReader::NewFloat32x4(float v0, float v1, float v2,
float v3) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawFloat32x4* obj = reinterpret_cast<RawFloat32x4*>(
AllocateUninitialized(kFloat32x4Cid, Float32x4::InstanceSize()));
obj->ptr()->value_[0] = v0;
@@ -842,7 +972,7 @@
RawInt32x4* SnapshotReader::NewInt32x4(uint32_t v0, uint32_t v1, uint32_t v2,
uint32_t v3) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawInt32x4* obj = reinterpret_cast<RawInt32x4*>(
AllocateUninitialized(kInt32x4Cid, Int32x4::InstanceSize()));
obj->ptr()->value_[0] = v0;
@@ -855,7 +985,7 @@
RawFloat64x2* SnapshotReader::NewFloat64x2(double v0, double v1) {
ASSERT(kind_ == Snapshot::kFull);
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
RawFloat64x2* obj = reinterpret_cast<RawFloat64x2*>(
AllocateUninitialized(kFloat64x2Cid, Float64x2::InstanceSize()));
obj->ptr()->value_[0] = v0;
@@ -914,7 +1044,7 @@
RawObject* SnapshotReader::AllocateUninitialized(intptr_t class_id,
intptr_t size) {
- ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+ ASSERT_NO_SAFEPOINT_SCOPE();
ASSERT(Utils::IsAligned(size, kObjectAlignment));
// Allocate memory where all words look like smis. This is currently
@@ -987,7 +1117,9 @@
}
-RawObject* SnapshotReader::ReadIndexedObject(intptr_t object_id) {
+RawObject* SnapshotReader::ReadIndexedObject(intptr_t object_id,
+ intptr_t patch_object_id,
+ intptr_t patch_offset) {
intptr_t class_id = ClassIdFromObjectId(object_id);
if (IsObjectStoreClassId(class_id)) {
return isolate()->class_table()->At(class_id); // get singleton class.
@@ -1002,137 +1134,90 @@
if (index < max_vm_isolate_object_id_) {
return VmIsolateSnapshotObject(index);
}
+ AddPatchRecord(object_id, patch_object_id, patch_offset);
return GetBackRef(object_id)->raw();
}
-RawObject* SnapshotReader::ReadInlinedObject(intptr_t object_id) {
- // Read the class header information and lookup the class.
- intptr_t class_header = Read<int32_t>();
- intptr_t tags = ReadTags();
- intptr_t header_id = SerializedHeaderData::decode(class_header);
- if (header_id == kInstanceObjectId) {
- // Object is regular dart instance.
- Instance* result = reinterpret_cast<Instance*>(GetBackRef(object_id));
- intptr_t instance_size = 0;
- if (result == NULL) {
- result = &(Instance::ZoneHandle(zone(), Instance::null()));
- AddBackRef(object_id, result, kIsDeserialized);
- cls_ ^= ReadObjectImpl();
- ASSERT(!cls_.IsNull());
- instance_size = cls_.instance_size();
- ASSERT(instance_size > 0);
- // Allocate the instance and read in all the fields for the object.
- if (kind_ == Snapshot::kFull) {
- *result ^= AllocateUninitialized(cls_.id(), instance_size);
- } else {
- *result ^= Object::Allocate(cls_.id(),
- instance_size,
- HEAP_SPACE(kind_));
- }
- } else {
- cls_ ^= ReadObjectImpl();
- ASSERT(!cls_.IsNull());
- instance_size = cls_.instance_size();
- }
- intptr_t next_field_offset = cls_.next_field_offset();
- intptr_t type_argument_field_offset = cls_.type_arguments_field_offset();
- ASSERT(next_field_offset > 0);
- // Instance::NextFieldOffset() returns the offset of the first field in
- // a Dart object.
- bool is_canonical = RawObject::IsCanonical(tags);
- intptr_t offset = Instance::NextFieldOffset();
- intptr_t result_cid = result->GetClassId();
- while (offset < next_field_offset) {
- pobj_ = is_canonical ? ReadObjectImpl() : ReadObjectRef();
- result->SetFieldAtOffset(offset, pobj_);
- if ((offset != type_argument_field_offset) &&
- (kind_ == Snapshot::kMessage)) {
- // TODO(fschneider): Consider hoisting these lookups out of the loop.
- // This would involve creating a handle, since cls_ can't be reused
- // across the call to ReadObjectRef.
- cls_ = isolate()->class_table()->At(result_cid);
- array_ = cls_.OffsetToFieldMap();
- field_ ^= array_.At(offset >> kWordSizeLog2);
- ASSERT(!field_.IsNull());
- ASSERT(field_.Offset() == offset);
- obj_ = pobj_.raw();
- field_.RecordStore(obj_);
- }
- // TODO(fschneider): Verify the guarded cid and length for other kinds of
- // snapshot (kFull, kScript) with asserts.
- offset += kWordSize;
- }
- if (kind_ == Snapshot::kFull) {
- // We create an uninitialized object in the case of full snapshots, so
- // we need to initialize any remaining padding area with the Null object.
- while (offset < instance_size) {
- result->SetFieldAtOffset(offset, Object::null_object());
- offset += kWordSize;
- }
- result->SetCreatedFromSnapshot();
- } else if (RawObject::IsCanonical(tags)) {
- *result = result->CheckAndCanonicalize(NULL);
- ASSERT(!result->IsNull());
- }
- return result->raw();
- } else if (header_id == kStaticImplicitClosureObjectId) {
- // We do not use the tags as the implicit static closure
- // is going to be created in this isolate or the canonical
- // version already created in the isolate will be used.
- return ReadStaticImplicitClosure(object_id, class_header);
+void SnapshotReader::AddPatchRecord(intptr_t object_id,
+ intptr_t patch_object_id,
+ intptr_t patch_offset) {
+ if (patch_object_id != kInvalidPatchIndex && kind() != Snapshot::kFull) {
+ ASSERT(object_id >= kMaxPredefinedObjectIds);
+ intptr_t index = (object_id - kMaxPredefinedObjectIds);
+ ASSERT(index >= max_vm_isolate_object_id_);
+ index -= max_vm_isolate_object_id_;
+ ASSERT(index < backward_references_->length());
+ BackRefNode& ref = (*backward_references_)[index];
+ ref.AddPatchRecord(patch_object_id, patch_offset);
}
- ASSERT((class_header & kSmiTagMask) != kSmiTag);
- intptr_t class_id = LookupInternalClass(class_header);
- switch (class_id) {
-#define SNAPSHOT_READ(clazz) \
- case clazz::kClassId: { \
- pobj_ = clazz::ReadFrom(this, object_id, tags, kind_); \
- break; \
- }
- CLASS_LIST_NO_OBJECT(SNAPSHOT_READ)
-#undef SNAPSHOT_READ
-#define SNAPSHOT_READ(clazz) \
- case kTypedData##clazz##Cid: \
-
- CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
- tags = RawObject::ClassIdTag::update(class_id, tags);
- pobj_ = TypedData::ReadFrom(this, object_id, tags, kind_);
- break;
- }
-#undef SNAPSHOT_READ
-#define SNAPSHOT_READ(clazz) \
- case kExternalTypedData##clazz##Cid: \
-
- CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
- tags = RawObject::ClassIdTag::update(class_id, tags);
- pobj_ = ExternalTypedData::ReadFrom(this, object_id, tags, kind_);
- break;
- }
-#undef SNAPSHOT_READ
- default: UNREACHABLE(); break;
- }
- if (kind_ == Snapshot::kFull) {
- pobj_.SetCreatedFromSnapshot();
- }
- return pobj_.raw();
}
-void SnapshotReader::ArrayReadFrom(const Array& result,
+void SnapshotReader::ProcessDeferredCanonicalizations() {
+ AbstractType& typeobj = AbstractType::Handle();
+ TypeArguments& typeargs = TypeArguments::Handle();
+ Object& newobj = Object::Handle();
+ for (intptr_t i = 0; i < backward_references_->length(); i++) {
+ BackRefNode& backref = (*backward_references_)[i];
+ if (backref.defer_canonicalization()) {
+ Object* objref = backref.reference();
+ // Object should either be an abstract type or a type argument.
+ if (objref->IsAbstractType()) {
+ typeobj ^= objref->raw();
+ typeobj.ClearCanonical();
+ newobj = typeobj.Canonicalize();
+ } else {
+ ASSERT(objref->IsTypeArguments());
+ typeargs ^= objref->raw();
+ typeargs.ClearCanonical();
+ newobj = typeargs.Canonicalize();
+ }
+ if (newobj.raw() == objref->raw()) {
+ // Restore Canonical bit.
+ objref->SetCanonical();
+ } else {
+ ZoneGrowableArray<intptr_t>* patches = backref.patch_records();
+ ASSERT(newobj.IsCanonical());
+ ASSERT(patches != NULL);
+ for (intptr_t j = 0; j < patches->length(); j+=2) {
+ NoSafepointScope no_safepoint;
+ intptr_t patch_object_id = (*patches)[j];
+ intptr_t patch_offset = (*patches)[j + 1];
+ Object* target = GetBackRef(patch_object_id);
+ RawObject** rawptr =
+ reinterpret_cast<RawObject**>(target->raw()->ptr());
+ target->StorePointer((rawptr + patch_offset), newobj.raw());
+ }
+ }
+ }
+ }
+}
+
+
+void SnapshotReader::ArrayReadFrom(intptr_t object_id,
+ const Array& result,
intptr_t len,
intptr_t tags) {
// Set the object tags.
result.set_tags(tags);
// Setup the object fields.
- *TypeArgumentsHandle() ^= ReadObjectImpl();
+ const intptr_t typeargs_offset =
+ reinterpret_cast<RawObject**>(&result.raw()->ptr()->type_arguments_) -
+ reinterpret_cast<RawObject**>(result.raw()->ptr());
+ *TypeArgumentsHandle() ^= ReadObjectImpl(kAsInlinedObject,
+ object_id,
+ typeargs_offset);
result.SetTypeArguments(*TypeArgumentsHandle());
- bool is_canonical = RawObject::IsCanonical(tags);
-
+ bool as_reference = RawObject::IsCanonical(tags) ? false : true;
+ intptr_t offset = result.raw_ptr()->data() -
+ reinterpret_cast<RawObject**>(result.raw()->ptr());
for (intptr_t i = 0; i < len; i++) {
- *PassiveObjectHandle() = is_canonical ? ReadObjectImpl() : ReadObjectRef();
+ *PassiveObjectHandle() = ReadObjectImpl(as_reference,
+ object_id,
+ (i + offset));
result.SetAt(i, *PassiveObjectHandle());
}
}
@@ -1279,7 +1364,7 @@
void SnapshotWriter::WriteObject(RawObject* rawobj) {
- WriteObjectImpl(rawobj);
+ WriteObjectImpl(rawobj, kAsInlinedObject);
WriteForwardedObjects();
}
@@ -1402,104 +1487,6 @@
#undef VM_OBJECT_WRITE
-void SnapshotWriter::WriteObjectRef(RawObject* raw) {
- // First check if object can be written as a simple predefined type.
- if (CheckAndWritePredefinedObject(raw)) {
- return;
- }
-
- NoSafepointScope no_safepoint;
- RawClass* cls = class_table_->At(raw->GetClassId());
- intptr_t class_id = cls->ptr()->id_;
- ASSERT(class_id == raw->GetClassId());
- if (class_id >= kNumPredefinedCids) {
- WriteInstanceRef(raw, cls);
- return;
- }
- if (class_id == kArrayCid) {
- // Object is being referenced, add it to the forward ref list and mark
- // it so that future references to this object in the snapshot will use
- // this object id. Mark it as not having been serialized yet so that we
- // will serialize the object when we go through the forward list.
- forward_list_->MarkAndAddObject(raw, kIsNotSerialized);
-
- RawArray* rawarray = reinterpret_cast<RawArray*>(raw);
-
- // Write out the serialization header value for this object.
- WriteInlinedObjectHeader(kOmittedObjectId);
-
- // Write out the class information.
- WriteIndexedObject(kArrayCid);
-
- // Write out the length field.
- Write<RawObject*>(rawarray->ptr()->length_);
-
- return;
- }
- if (class_id == kImmutableArrayCid) {
- // Object is being referenced, add it to the forward ref list and mark
- // it so that future references to this object in the snapshot will use
- // this object id. Mark it as not having been serialized yet so that we
- // will serialize the object when we go through the forward list.
- forward_list_->MarkAndAddObject(raw, kIsNotSerialized);
-
- RawArray* rawarray = reinterpret_cast<RawArray*>(raw);
-
- // Write out the serialization header value for this object.
- WriteInlinedObjectHeader(kOmittedObjectId);
-
- // Write out the class information.
- WriteIndexedObject(kImmutableArrayCid);
-
- // Write out the length field.
- Write<RawObject*>(rawarray->ptr()->length_);
-
- return;
- }
- if (RawObject::IsImplicitFieldClassId(class_id)) {
- WriteInstanceRef(raw, cls);
- return;
- }
- // Add object to the forward ref list and mark it so that future references
- // to this object in the snapshot will use this object id. Mark it as having
- // been serialized so that we do not serialize the object when we go through
- // the forward list.
- forward_list_->MarkAndAddObject(raw, kIsSerialized);
- switch (class_id) {
-#define SNAPSHOT_WRITE(clazz) \
- case clazz::kClassId: { \
- Raw##clazz* raw_obj = reinterpret_cast<Raw##clazz*>(raw); \
- raw_obj->WriteTo(this, kOmittedObjectId, kind_); \
- return; \
- } \
-
- CLASS_LIST_NO_OBJECT(SNAPSHOT_WRITE)
-#undef SNAPSHOT_WRITE
-#define SNAPSHOT_WRITE(clazz) \
- case kTypedData##clazz##Cid: \
-
- CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
- RawTypedData* raw_obj = reinterpret_cast<RawTypedData*>(raw);
- raw_obj->WriteTo(this, kOmittedObjectId, kind_);
- return;
- }
-#undef SNAPSHOT_WRITE
-#define SNAPSHOT_WRITE(clazz) \
- case kExternalTypedData##clazz##Cid: \
-
- CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
- RawExternalTypedData* raw_obj =
- reinterpret_cast<RawExternalTypedData*>(raw);
- raw_obj->WriteTo(this, kOmittedObjectId, kind_);
- return;
- }
-#undef SNAPSHOT_WRITE
- default: break;
- }
- UNREACHABLE();
-}
-
-
// An object visitor which will iterate over all the script objects in the heap
// and either count them or collect them into an array. This is used during
// full snapshot generation of the VM isolate to write out all script
@@ -1703,14 +1690,15 @@
first_unprocessed_object_id_(first_object_id) {
// The ForwardList encodes information in the header tag word. There cannot
// be any concurrent GC tasks while it is in use.
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
PageSpace* page_space = isolate->heap()->old_space();
MonitorLocker ml(page_space->tasks_lock());
while (page_space->tasks() > 0) {
ml.Wait();
}
// Ensure that no GC happens while we are writing out the full snapshot.
- isolate->IncrementNoSafepointScopeDepth();
+ thread->IncrementNoSafepointScopeDepth();
}
@@ -1769,7 +1757,7 @@
raw->ptr()->tags_ = node->tags(); // Restore original tags.
}
}
- Isolate::Current()->DecrementNoSafepointScopeDepth();
+ Thread::Current()->DecrementNoSafepointScopeDepth();
}
@@ -1847,18 +1835,95 @@
}
-void SnapshotWriter::WriteObjectImpl(RawObject* raw) {
+void SnapshotWriter::WriteObjectImpl(RawObject* raw, bool as_reference) {
// First check if object can be written as a simple predefined type.
if (CheckAndWritePredefinedObject(raw)) {
return;
}
- // Object is being serialized, add it to the forward ref list and mark
- // it so that future references to this object in the snapshot will use
- // an object id, instead of trying to serialize it again.
- forward_list_->MarkAndAddObject(raw, kIsSerialized);
+ if (as_reference && !raw->IsCanonical()) {
+ WriteObjectRef(raw);
+ } else {
+ // Object is being serialized, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // an object id, instead of trying to serialize it again.
+ forward_list_->MarkAndAddObject(raw, kIsSerialized);
- WriteInlinedObject(raw);
+ WriteInlinedObject(raw);
+ }
+}
+
+
+void SnapshotWriter::WriteObjectRef(RawObject* raw) {
+ NoSafepointScope no_safepoint;
+ RawClass* cls = class_table_->At(raw->GetClassId());
+ intptr_t class_id = cls->ptr()->id_;
+ ASSERT(class_id == raw->GetClassId());
+ if (class_id >= kNumPredefinedCids ||
+ RawObject::IsImplicitFieldClassId(class_id)) {
+ WriteInstanceRef(raw, cls);
+ return;
+ }
+ if (class_id == kArrayCid || class_id == kImmutableArrayCid) {
+ intptr_t tags = GetObjectTags(raw);
+
+ // Object is being referenced, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // this object id. Mark it as not having been serialized yet so that we
+ // will serialize the object when we go through the forward list.
+ forward_list_->MarkAndAddObject(raw, kIsNotSerialized);
+
+ RawArray* rawarray = reinterpret_cast<RawArray*>(raw);
+
+ // Write out the serialization header value for this object.
+ WriteInlinedObjectHeader(kOmittedObjectId);
+
+ // Write out the class information.
+ WriteIndexedObject(class_id);
+ WriteTags(tags);
+
+ // Write out the length field.
+ Write<RawObject*>(rawarray->ptr()->length_);
+
+ return;
+ }
+ // Add object to the forward ref list and mark it so that future references
+ // to this object in the snapshot will use this object id. Mark it as having
+ // been serialized so that we do not serialize the object when we go through
+ // the forward list.
+ forward_list_->MarkAndAddObject(raw, kIsSerialized);
+ switch (class_id) {
+#define SNAPSHOT_WRITE(clazz) \
+ case clazz::kClassId: { \
+ Raw##clazz* raw_obj = reinterpret_cast<Raw##clazz*>(raw); \
+ raw_obj->WriteTo(this, kOmittedObjectId, kind_); \
+ return; \
+ } \
+
+ CLASS_LIST_NO_OBJECT(SNAPSHOT_WRITE)
+#undef SNAPSHOT_WRITE
+#define SNAPSHOT_WRITE(clazz) \
+ case kTypedData##clazz##Cid: \
+
+ CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
+ RawTypedData* raw_obj = reinterpret_cast<RawTypedData*>(raw);
+ raw_obj->WriteTo(this, kOmittedObjectId, kind_);
+ return;
+ }
+#undef SNAPSHOT_WRITE
+#define SNAPSHOT_WRITE(clazz) \
+ case kExternalTypedData##clazz##Cid: \
+
+ CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
+ RawExternalTypedData* raw_obj =
+ reinterpret_cast<RawExternalTypedData*>(raw);
+ raw_obj->WriteTo(this, kOmittedObjectId, kind_);
+ return;
+ }
+#undef SNAPSHOT_WRITE
+ default: break;
+ }
+ UNREACHABLE();
}
@@ -1988,8 +2053,8 @@
// Write out the library url and class name.
RawLibrary* library = cls->ptr()->library_;
ASSERT(library != Library::null());
- WriteObjectImpl(library->ptr()->url_);
- WriteObjectImpl(cls->ptr()->name_);
+ WriteObjectImpl(library->ptr()->url_, kAsInlinedObject);
+ WriteObjectImpl(cls->ptr()->name_, kAsInlinedObject);
}
@@ -2010,9 +2075,9 @@
ASSERT(cls != Class::null());
RawLibrary* library = cls->ptr()->library_;
ASSERT(library != Library::null());
- WriteObjectImpl(library->ptr()->url_);
- WriteObjectImpl(cls->ptr()->name_);
- WriteObjectImpl(func->ptr()->name_);
+ WriteObjectImpl(library->ptr()->url_, kAsInlinedObject);
+ WriteObjectImpl(cls->ptr()->name_, kAsInlinedObject);
+ WriteObjectImpl(func->ptr()->name_, kAsInlinedObject);
}
@@ -2035,16 +2100,12 @@
Write<RawObject*>(length);
// Write out the type arguments.
- WriteObjectImpl(type_arguments);
+ WriteObjectImpl(type_arguments, kAsInlinedObject);
// Write out the individual object ids.
- bool is_canonical = RawObject::IsCanonical(tags);
+ bool as_reference = RawObject::IsCanonical(tags) ? false : true;
for (intptr_t i = 0; i < len; i++) {
- if (is_canonical) {
- WriteObjectImpl(data[i]);
- } else {
- WriteObjectRef(data[i]);
- }
+ WriteObjectImpl(data[i], as_reference);
}
}
@@ -2153,21 +2214,17 @@
WriteTags(tags);
// Write out the class information for this object.
- WriteObjectImpl(cls);
+ WriteObjectImpl(cls, kAsInlinedObject);
// Write out all the fields for the object.
// Instance::NextFieldOffset() returns the offset of the first field in
// a Dart object.
- bool is_canonical = RawObject::IsCanonical(tags);
+ bool as_reference = RawObject::IsCanonical(tags) ? false : true;
intptr_t offset = Instance::NextFieldOffset();
while (offset < next_field_offset) {
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
reinterpret_cast<uword>(raw->ptr()) + offset);
- if (is_canonical) {
- WriteObjectImpl(raw_obj);
- } else {
- WriteObjectRef(raw_obj);
- }
+ WriteObjectImpl(raw_obj, as_reference);
offset += kWordSize;
}
return;
@@ -2199,6 +2256,7 @@
// it so that future references to this object in the snapshot will use
// this object id. Mark it as not having been serialized yet so that we
// will serialize the object when we go through the forward list.
+ intptr_t tags = raw->ptr()->tags_;
forward_list_->MarkAndAddObject(raw, kIsNotSerialized);
// Write out the serialization header value for this object.
@@ -2206,9 +2264,10 @@
// Indicate this is an instance object.
Write<int32_t>(SerializedHeaderData::encode(kInstanceObjectId));
+ WriteTags(tags);
// Write out the class information for this object.
- WriteObjectImpl(cls);
+ WriteObjectImpl(cls, kAsInlinedObject);
}
@@ -2307,11 +2366,7 @@
void SnapshotWriterVisitor::VisitPointers(RawObject** first, RawObject** last) {
for (RawObject** current = first; current <= last; current++) {
RawObject* raw_obj = *current;
- if (as_references_) {
- writer_->WriteObjectRef(raw_obj);
- } else {
- writer_->WriteObjectImpl(raw_obj);
- }
+ writer_->WriteObjectImpl(raw_obj, as_references_);
}
}
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 1989c7b..161da59 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -97,6 +97,9 @@
static const int8_t kHeaderTagBits = 2;
static const int8_t kObjectIdBits = (kBitsPerInt32 - (kHeaderTagBits + 1));
static const intptr_t kMaxObjectId = (kMaxUint32 >> (kHeaderTagBits + 1));
+static const bool kAsReference = true;
+static const bool kAsInlinedObject = false;
+static const intptr_t kInvalidPatchIndex = -1;
class SerializedHeaderTag : public BitField<enum SerializedHeaderType,
@@ -248,21 +251,42 @@
class BackRefNode : public ValueObject {
public:
- BackRefNode(Object* reference, DeserializeState state)
- : reference_(reference), state_(state) {}
+ BackRefNode(Object* reference,
+ DeserializeState state,
+ bool defer_canonicalization)
+ : reference_(reference),
+ state_(state),
+ defer_canonicalization_(defer_canonicalization),
+ patch_records_(NULL) {}
Object* reference() const { return reference_; }
bool is_deserialized() const { return state_ == kIsDeserialized; }
void set_state(DeserializeState state) { state_ = state; }
+ bool defer_canonicalization() const { return defer_canonicalization_; }
+ ZoneGrowableArray<intptr_t>* patch_records() const { return patch_records_; }
BackRefNode& operator=(const BackRefNode& other) {
reference_ = other.reference_;
state_ = other.state_;
+ defer_canonicalization_ = other.defer_canonicalization_;
+ patch_records_ = other.patch_records_;
return *this;
}
+ void AddPatchRecord(intptr_t patch_object_id, intptr_t patch_offset) {
+ if (defer_canonicalization_) {
+ if (patch_records_ == NULL) {
+ patch_records_ = new ZoneGrowableArray<intptr_t>();
+ }
+ patch_records_->Add(patch_object_id);
+ patch_records_->Add(patch_offset);
+ }
+ }
+
private:
Object* reference_;
DeserializeState state_;
+ bool defer_canonicalization_;
+ ZoneGrowableArray<intptr_t>* patch_records_;
};
@@ -290,7 +314,10 @@
RawObject* ReadObject();
// Add object to backward references.
- void AddBackRef(intptr_t id, Object* obj, DeserializeState state);
+ void AddBackRef(intptr_t id,
+ Object* obj,
+ DeserializeState state,
+ bool defer_canonicalization = false);
// Get an object from the backward references list.
Object* GetBackRef(intptr_t id);
@@ -367,24 +394,55 @@
RawClass* ReadClassId(intptr_t object_id);
RawObject* ReadStaticImplicitClosure(intptr_t object_id, intptr_t cls_header);
- RawObject* ReadObjectImpl();
- RawObject* ReadObjectImpl(intptr_t header);
- RawObject* ReadObjectRef();
+
+ // Implementation to read an object.
+ RawObject* ReadObjectImpl(bool as_reference,
+ intptr_t patch_object_id = kInvalidPatchIndex,
+ intptr_t patch_offset = 0);
+ RawObject* ReadObjectImpl(intptr_t header,
+ bool as_reference,
+ intptr_t patch_object_id,
+ intptr_t patch_offset);
+
+ // Read an object reference from the stream.
+ RawObject* ReadObjectRef(intptr_t object_id,
+ intptr_t class_header,
+ intptr_t tags,
+ intptr_t patch_object_id = kInvalidPatchIndex,
+ intptr_t patch_offset = 0);
+
+ // Read an inlined object from the stream.
+ RawObject* ReadInlinedObject(intptr_t object_id,
+ intptr_t class_header,
+ intptr_t tags,
+ intptr_t patch_object_id,
+ intptr_t patch_offset);
// Read a VM isolate object that was serialized as an Id.
RawObject* ReadVMIsolateObject(intptr_t object_id);
// Read an object that was serialized as an Id (singleton in object store,
// or an object that was already serialized before).
- RawObject* ReadIndexedObject(intptr_t object_id);
+ RawObject* ReadIndexedObject(intptr_t object_id,
+ intptr_t patch_object_id,
+ intptr_t patch_offset);
- // Read an inlined object from the stream.
- RawObject* ReadInlinedObject(intptr_t object_id);
+ // Add a patch record for the object so that objects whose canonicalization
+ // is deferred can be back patched after they are canonicalized.
+ void AddPatchRecord(intptr_t object_id,
+ intptr_t patch_object_id,
+ intptr_t patch_offset);
+
+ // Process all the deferred canonicalization entries and patch all references.
+ void ProcessDeferredCanonicalizations();
// Decode class id from the header field.
intptr_t LookupInternalClass(intptr_t class_header);
- void ArrayReadFrom(const Array& result, intptr_t len, intptr_t tags);
+ void ArrayReadFrom(intptr_t object_id,
+ const Array& result,
+ intptr_t len,
+ intptr_t tags);
intptr_t NextAvailableObjectId() const;
@@ -703,12 +761,12 @@
bool CheckAndWritePredefinedObject(RawObject* raw);
void HandleVMIsolateObject(RawObject* raw);
- void WriteObjectRef(RawObject* raw);
void WriteClassId(RawClass* cls);
void WriteStaticImplicitClosure(intptr_t object_id,
RawFunction* func,
intptr_t tags);
- void WriteObjectImpl(RawObject* raw);
+ void WriteObjectImpl(RawObject* raw, bool as_reference);
+ void WriteObjectRef(RawObject* raw);
void WriteInlinedObject(RawObject* raw);
void WriteForwardedObjects();
void ArrayWriteTo(intptr_t object_id,
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 23c687a..2843561 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -120,6 +120,9 @@
second->value.as_array.values[i]);
}
break;
+ case Dart_CObject_kCapability:
+ EXPECT_EQ(first->value.as_capability.id, second->value.as_capability.id);
+ break;
default:
EXPECT(false);
}
@@ -402,6 +405,38 @@
}
+TEST_CASE(SerializeCapability) {
+ StackZone zone(Isolate::Current());
+
+ // Write snapshot with object content.
+ const Capability& capability = Capability::Handle(Capability::New(12345));
+ uint8_t* buffer;
+ MessageWriter writer(&buffer, &zone_allocator, true);
+ writer.WriteMessage(capability);
+ intptr_t buffer_len = writer.BytesWritten();
+
+ // Read object back from the snapshot.
+ MessageSnapshotReader reader(buffer,
+ buffer_len,
+ Isolate::Current(),
+ zone.GetZone());
+ Capability& obj = Capability::Handle();
+ obj ^= reader.ReadObject();
+
+ EXPECT_STREQ(12345, obj.Id());
+
+ // Read object back from the snapshot into a C structure.
+ ApiNativeScope scope;
+ ApiMessageReader api_reader(buffer, buffer_len, &zone_allocator);
+ Dart_CObject* root = api_reader.ReadMessage();
+ EXPECT_NOTNULL(root);
+ EXPECT_EQ(Dart_CObject_kCapability, root->type);
+ int64_t id = root->value.as_capability.id;
+ EXPECT_EQ(12345, id);
+ CheckEncodeDecodeMessage(root);
+}
+
+
TEST_CASE(SerializeBigint) {
StackZone zone(Isolate::Current());
@@ -1020,6 +1055,120 @@
}
+#if 0
+UNIT_TEST_CASE(CanonicalizationInScriptSnapshots) {
+ const char* kScriptChars =
+ "\n"
+ "import 'dart:mirrors';"
+ "import 'dart:isolate';"
+ "void main() {"
+ " if (reflectClass(MyException).superclass.reflectedType != "
+ " IsolateSpawnException) {"
+ " throw new Exception('Canonicalization failure');"
+ " }"
+ " if (reflectClass(IsolateSpawnException).reflectedType != "
+ " IsolateSpawnException) {"
+ " throw new Exception('Canonicalization failure');"
+ " }"
+ "}\n"
+ "class MyException extends IsolateSpawnException {}"
+ "\n";
+
+ Dart_Handle result;
+
+ uint8_t* buffer;
+ intptr_t size;
+ intptr_t vm_isolate_snapshot_size;
+ uint8_t* isolate_snapshot = NULL;
+ intptr_t isolate_snapshot_size;
+ uint8_t* full_snapshot = NULL;
+ uint8_t* script_snapshot = NULL;
+
+ bool saved_load_deferred_eagerly_mode = FLAG_load_deferred_eagerly;
+ FLAG_load_deferred_eagerly = true;
+ // Workaround until issue 21620 is fixed.
+ // (https://github.com/dart-lang/sdk/issues/21620)
+ bool saved_concurrent_sweep_mode = FLAG_concurrent_sweep;
+ FLAG_concurrent_sweep = false;
+ {
+ // Start an Isolate, and create a full snapshot of it.
+ TestIsolateScope __test_isolate__;
+ Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
+
+ // Write out the script snapshot.
+ result = Dart_CreateSnapshot(NULL,
+ &vm_isolate_snapshot_size,
+ &isolate_snapshot,
+ &isolate_snapshot_size);
+ EXPECT_VALID(result);
+ full_snapshot = reinterpret_cast<uint8_t*>(malloc(isolate_snapshot_size));
+ memmove(full_snapshot, isolate_snapshot, isolate_snapshot_size);
+ Dart_ExitScope();
+ }
+ FLAG_load_deferred_eagerly = saved_load_deferred_eagerly_mode;
+ FLAG_concurrent_sweep = saved_concurrent_sweep_mode;
+
+ {
+ // Now Create an Isolate using the full snapshot and load the
+ // script and execute it.
+ TestCase::CreateTestIsolateFromSnapshot(full_snapshot);
+ Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
+
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
+ EXPECT_VALID(lib);
+
+ // Invoke a function which returns an object.
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ }
+
+ {
+ // Create an Isolate using the full snapshot, load a script and create
+ // a script snapshot of the script.
+ TestCase::CreateTestIsolateFromSnapshot(full_snapshot);
+ Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
+
+ // Create a test library and Load up a test script in it.
+ TestCase::LoadTestScript(kScriptChars, NULL);
+
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+
+ // Write out the script snapshot.
+ result = Dart_CreateScriptSnapshot(&buffer, &size);
+ EXPECT_VALID(result);
+ script_snapshot = reinterpret_cast<uint8_t*>(malloc(size));
+ memmove(script_snapshot, buffer, size);
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ }
+
+ {
+ // Now Create an Isolate using the full snapshot and load the
+ // script snapshot created above and execute it.
+ TestCase::CreateTestIsolateFromSnapshot(full_snapshot);
+ Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
+
+ // Load the test library from the snapshot.
+ EXPECT(script_snapshot != NULL);
+ result = Dart_LoadScriptFromSnapshot(script_snapshot, size);
+ EXPECT_VALID(result);
+
+ // Invoke a function which returns an object.
+ result = Dart_Invoke(result, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ }
+ free(script_snapshot);
+ free(full_snapshot);
+}
+#endif
+
+
static void IterateScripts(const Library& lib) {
const Array& lib_scripts = Array::Handle(lib.LoadedScripts());
Script& script = Script::Handle();
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index dd849e5..94ba9d3 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -144,7 +144,7 @@
class EntryFrame : public StackFrame {
public:
bool IsValid() const {
- return StubCode::InInvocationStubForIsolate(isolate(), pc());
+ return StubCode::InInvocationStub(pc());
}
bool IsDartFrame(bool validate = true) const { return false; }
bool IsStubFrame() const { return false; }
@@ -206,7 +206,7 @@
}
const uword pc = *(reinterpret_cast<uword*>(
sp_ + (kSavedPcSlotFromSp * kWordSize)));
- return !StubCode::InInvocationStubForIsolate(isolate_, pc);
+ return !StubCode::InInvocationStub(pc);
}
// Get next non entry/exit frame in the set (assumes a next frame exists).
diff --git a/runtime/vm/store_buffer.cc b/runtime/vm/store_buffer.cc
index a590c28..f4fbad7 100644
--- a/runtime/vm/store_buffer.cc
+++ b/runtime/vm/store_buffer.cc
@@ -78,9 +78,14 @@
MutexLocker ml(mutex_);
partial_.Push(block);
}
- if (check_threshold) {
+ if (check_threshold && Overflowed()) {
MutexLocker ml(mutex_);
- CheckThresholdNonEmpty();
+ Isolate* isolate = Isolate::Current();
+ // Sanity check: it makes no sense to schedule the GC in another isolate.
+ // (If Isolate ever gets multiple store buffers, we should avoid this
+ // coupling by passing in an explicit callback+parameter at construction.)
+ ASSERT(isolate->store_buffer() == this);
+ isolate->ScheduleInterrupts(Isolate::kVMInterrupt);
}
}
@@ -139,16 +144,9 @@
}
-void StoreBuffer::CheckThresholdNonEmpty() {
- DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
- if (full_.length() + partial_.length() > kMaxNonEmpty) {
- Isolate* isolate = Isolate::Current();
- // Sanity check: it makes no sense to schedule the GC in another isolate.
- // (If Isolate ever gets multiple store buffers, we should avoid this
- // coupling by passing in an explicit callback+parameter at construction.)
- ASSERT(isolate->store_buffer() == this);
- isolate->ScheduleInterrupts(Isolate::kStoreBufferInterrupt);
- }
+bool StoreBuffer::Overflowed() {
+ MutexLocker ml(mutex_);
+ return (full_.length() + partial_.length()) > kMaxNonEmpty;
}
diff --git a/runtime/vm/store_buffer.h b/runtime/vm/store_buffer.h
index b8f36a5..b1bd387 100644
--- a/runtime/vm/store_buffer.h
+++ b/runtime/vm/store_buffer.h
@@ -97,6 +97,9 @@
// Discards the contents of this store buffer.
void Reset();
+ // Check whether non-empty blocks have exceeded kMaxNonEmpty.
+ bool Overflowed();
+
private:
class List {
public:
@@ -113,10 +116,6 @@
DISALLOW_COPY_AND_ASSIGN(List);
};
- // Check if we run over the max number of deduplication sets.
- // If we did schedule an interrupt.
- void CheckThresholdNonEmpty();
-
// If needed, trims the the global cache of empty blocks.
static void TrimGlobalEmpty();
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index ad51097..486531a 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -38,14 +38,6 @@
}
-StubCode::~StubCode() {
-#define STUB_CODE_DELETER(name) \
- delete name##_entry_;
- STUB_CODE_LIST(STUB_CODE_DELETER);
-#undef STUB_CODE_DELETER
-}
-
-
#define STUB_CODE_GENERATE(name) \
code ^= Generate("_stub_"#name, StubCode::Generate##name##Stub); \
name##_entry_ = new StubEntry(code);
@@ -58,83 +50,45 @@
}
-void StubCode::GenerateStubsFor(Isolate* init) {
- // Generate all the other stubs.
- Code& code = Code::Handle();
- STUB_CODE_LIST(STUB_CODE_GENERATE);
-}
-
#undef STUB_CODE_GENERATE
-void StubCode::Init(Isolate* isolate) {
- StubCode* stubs = new StubCode(isolate);
- isolate->set_stub_code(stubs);
- isolate->stub_code()->GenerateStubsFor(isolate);
-}
+void StubCode::Init(Isolate* isolate) { }
void StubCode::VisitObjectPointers(ObjectPointerVisitor* visitor) {
- // The current isolate is needed as part of the macro.
- Isolate* isolate = Isolate::Current();
- StubCode* stubs = isolate->stub_code();
- if (stubs == NULL) return;
- StubEntry* entry;
-#define STUB_CODE_VISIT_OBJECT_POINTER(name) \
- entry = stubs->name##_entry(); \
- if (entry != NULL) { \
- entry->VisitObjectPointers(visitor); \
- }
-
- STUB_CODE_LIST(STUB_CODE_VISIT_OBJECT_POINTER);
-#undef STUB_CODE_VISIT_OBJECT_POINTER
}
bool StubCode::InInvocationStub(uword pc) {
- return InInvocationStubForIsolate(Isolate::Current(), pc);
-}
-
-
-bool StubCode::InInvocationStubForIsolate(Isolate* isolate, uword pc) {
- StubCode* stub_code = isolate->stub_code();
- uword entry = stub_code->InvokeDartCodeEntryPoint();
- uword size = stub_code->InvokeDartCodeSize();
+ uword entry = StubCode::InvokeDartCode_entry()->EntryPoint();
+ uword size = StubCode::InvokeDartCodeSize();
return (pc >= entry) && (pc < (entry + size));
}
bool StubCode::InJumpToExceptionHandlerStub(uword pc) {
- uword entry = StubCode::JumpToExceptionHandlerEntryPoint();
+ uword entry = StubCode::JumpToExceptionHandler_entry()->EntryPoint();
uword size = StubCode::JumpToExceptionHandlerSize();
return (pc >= entry) && (pc < (entry + size));
}
-RawCode* StubCode::GetAllocateArrayStub() {
- const Class& array_cls = Class::Handle(isolate_,
- isolate_->object_store()->array_class());
- return GetAllocationStubForClass(array_cls);
-}
-
-
RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
Isolate* isolate = Isolate::Current();
const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
ASSERT(error.IsNull());
+ if (cls.id() == kArrayCid) {
+ return AllocateArray_entry()->code();
+ }
Code& stub = Code::Handle(isolate, cls.allocation_stub());
if (stub.IsNull()) {
Assembler assembler;
const char* name = cls.ToCString();
uword patch_code_offset = 0;
uword entry_patch_offset = 0;
- if (cls.id() == kArrayCid) {
- StubCode::GeneratePatchableAllocateArrayStub(
- &assembler, &entry_patch_offset, &patch_code_offset);
- } else {
- StubCode::GenerateAllocationStubForClass(
- &assembler, cls, &entry_patch_offset, &patch_code_offset);
- }
+ StubCode::GenerateAllocationStubForClass(
+ &assembler, cls, &entry_patch_offset, &patch_code_offset);
stub ^= Code::FinalizeCode(name, &assembler);
stub.set_owner(cls);
cls.set_allocation_stub(stub);
@@ -155,17 +109,18 @@
}
-uword StubCode::UnoptimizedStaticCallEntryPoint(intptr_t num_args_tested) {
+const StubEntry* StubCode::UnoptimizedStaticCallEntry(
+ intptr_t num_args_tested) {
switch (num_args_tested) {
case 0:
- return ZeroArgsUnoptimizedStaticCallEntryPoint();
+ return ZeroArgsUnoptimizedStaticCall_entry();
case 1:
- return OneArgUnoptimizedStaticCallEntryPoint();
+ return OneArgUnoptimizedStaticCall_entry();
case 2:
- return TwoArgsUnoptimizedStaticCallEntryPoint();
+ return TwoArgsUnoptimizedStaticCall_entry();
default:
UNIMPLEMENTED();
- return 0;
+ return NULL;
}
}
@@ -191,22 +146,12 @@
const char* StubCode::NameOfStub(uword entry_point) {
#define VM_STUB_CODE_TESTER(name) \
- if ((name##_entry() != NULL) && (entry_point == name##EntryPoint())) { \
+ if ((name##_entry() != NULL) && \
+ (entry_point == name##_entry()->EntryPoint())) { \
return ""#name; \
}
VM_STUB_CODE_LIST(VM_STUB_CODE_TESTER);
-
-#define STUB_CODE_TESTER(name) \
- if ((isolate->stub_code()->name##_entry() != NULL) && \
- (entry_point == isolate->stub_code()->name##EntryPoint())) { \
- return ""#name; \
- }
- Isolate* isolate = Isolate::Current();
- if ((isolate != NULL) && (isolate->stub_code() != NULL)) {
- STUB_CODE_LIST(STUB_CODE_TESTER);
- }
#undef VM_STUB_CODE_TESTER
-#undef STUB_CODE_TESTER
return NULL;
}
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index b383478..3a5ffc1 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -35,13 +35,14 @@
V(DebugStepCheck) \
V(MegamorphicLookup) \
V(FixAllocationStubTarget) \
- V(FixAllocateArrayStubTarget) \
V(Deoptimize) \
V(DeoptimizeLazy) \
V(UnoptimizedIdenticalWithNumberCheck) \
V(OptimizedIdenticalWithNumberCheck) \
V(ICCallBreakpoint) \
V(RuntimeCallBreakpoint) \
+ V(AllocateArray) \
+ V(AllocateContext) \
V(OneArgCheckInlineCache) \
V(TwoArgsCheckInlineCache) \
V(SmiAddInlineCache) \
@@ -57,7 +58,7 @@
V(Subtype1TestCache) \
V(Subtype2TestCache) \
V(Subtype3TestCache) \
- V(AllocateContext) \
+ V(CallClosureNoSuchMethod)
// Is it permitted for the stubs above to refer to Object::null(), which is
// allocated in the VM isolate and shared across all isolates.
@@ -65,12 +66,6 @@
// using Smi 0 instead of Object::null() is slightly more efficient, since a Smi
// does not require relocation.
-// List of stubs created per isolate, these stubs could potentially contain
-// embedded objects and hence cannot be shared across isolates.
-#define STUB_CODE_LIST(V) \
- V(CallClosureNoSuchMethod) \
-
-
// class StubEntry is used to describe stub methods generated in dart to
// abstract out common code executed from generated dart code.
class StubEntry {
@@ -97,17 +92,8 @@
// class StubCode is used to maintain the lifecycle of stubs.
-class StubCode {
+class StubCode : public AllStatic {
public:
- explicit StubCode(Isolate* isolate)
- :
-#define STUB_CODE_INITIALIZER(name) \
- name##_entry_(NULL),
- STUB_CODE_LIST(STUB_CODE_INITIALIZER)
- isolate_(isolate) {}
- ~StubCode();
-
-
// Generate all stubs which are shared across all isolates, this is done
// only once and the stub code resides in the vm_isolate heap.
static void InitOnce();
@@ -122,8 +108,6 @@
// transitioning into dart code.
static bool InInvocationStub(uword pc);
- static bool InInvocationStubForIsolate(Isolate* isolate, uword pc);
-
// Check if the specified pc is in the jump to exception handler stub.
static bool InJumpToExceptionHandlerStub(uword pc);
@@ -132,42 +116,18 @@
// Define the shared stub code accessors.
#define STUB_CODE_ACCESSOR(name) \
- static StubEntry* name##_entry() { \
+ static const StubEntry* name##_entry() { \
return name##_entry_; \
} \
- static const ExternalLabel& name##Label() { \
- return name##_entry()->label(); \
- } \
- static uword name##EntryPoint() { \
- return name##_entry()->EntryPoint(); \
- } \
static intptr_t name##Size() { \
return name##_entry()->Size(); \
}
VM_STUB_CODE_LIST(STUB_CODE_ACCESSOR);
#undef STUB_CODE_ACCESSOR
- // Define the per-isolate stub code accessors.
-#define STUB_CODE_ACCESSOR(name) \
- StubEntry* name##_entry() { \
- return name##_entry_; \
- } \
- const ExternalLabel& name##Label() { \
- return name##_entry()->label(); \
- } \
- uword name##EntryPoint() { \
- return name##_entry()->EntryPoint(); \
- } \
- intptr_t name##Size() { \
- return name##_entry()->Size(); \
- }
- STUB_CODE_LIST(STUB_CODE_ACCESSOR);
-#undef STUB_CODE_ACCESSOR
-
static RawCode* GetAllocationStubForClass(const Class& cls);
- RawCode* GetAllocateArrayStub();
- uword UnoptimizedStaticCallEntryPoint(intptr_t num_args_tested);
+ static const StubEntry* UnoptimizedStaticCallEntry(intptr_t num_args_tested);
static const intptr_t kNoInstantiator = 0;
@@ -175,8 +135,6 @@
Assembler*, Register recv, Register cache, Register target);
private:
- void GenerateStubsFor(Isolate* isolate);
-
friend class MegamorphicCacheTable;
static const intptr_t kStubCodeSize = 4 * KB;
@@ -184,7 +142,6 @@
#define STUB_CODE_GENERATE(name) \
static void Generate##name##Stub(Assembler* assembler);
VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
- STUB_CODE_LIST(STUB_CODE_GENERATE);
#undef STUB_CODE_GENERATE
#define STUB_CODE_ENTRY(name) \
@@ -192,12 +149,6 @@
VM_STUB_CODE_LIST(STUB_CODE_ENTRY);
#undef STUB_CODE_ENTRY
-#define STUB_CODE_ENTRY(name) \
- StubEntry* name##_entry_;
- STUB_CODE_LIST(STUB_CODE_ENTRY);
-#undef STUB_CODE_ENTRY
- Isolate* isolate_;
-
enum RangeCollectionMode {
kCollectRanges,
kIgnoreRanges
@@ -212,8 +163,6 @@
static void GenerateAllocationStubForClass(
Assembler* assembler, const Class& cls,
uword* entry_patch_offset, uword* patch_code_pc_offset);
- static void GeneratePatchableAllocateArrayStub(Assembler* assembler,
- uword* entry_patch_offset, uword* patch_code_pc_offset);
static void GenerateNArgsCheckInlineCacheStub(
Assembler* assembler,
intptr_t num_args,
@@ -224,13 +173,6 @@
static void GenerateUsageCounterIncrement(Assembler* assembler,
Register temp_reg);
static void GenerateOptimizedUsageCounterIncrement(Assembler* assembler);
-
- static void GenerateIdenticalWithNumberCheckStub(
- Assembler* assembler,
- const Register left,
- const Register right,
- const Register temp1 = kNoRegister,
- const Register temp2 = kNoRegister);
};
} // namespace dart
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 5d270ce..9459b29 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -358,39 +358,15 @@
}
-// Called from array allocate instruction when the allocation stub has been
-// disabled.
-// R1: element type (preserved).
-// R2: length (preserved).
-void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) {
- __ EnterStubFrame();
- // Setup space on stack for return value and preserve length, element type.
- __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
- __ PushList((1 << R0) | (1 << R1) | (1 << R2));
- __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
- // Get Code object result and restore length, element type.
- __ PopList((1 << R0) | (1 << R1) | (1 << R2));
- // Remove the stub frame.
- __ LeaveStubFrame();
- // Jump to the dart function.
- __ ldr(R0, FieldAddress(R0, Code::instructions_offset()));
- __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag);
- __ bx(R0);
-}
-
-
// Input parameters:
// R2: smi-tagged argument count, may be zero.
// FP[kParamEndSlotFromFp + 1]: last argument.
static void PushArgumentsArray(Assembler* assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
// Allocate array to store arguments of caller.
__ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
// R1: null element type for raw Array.
// R2: smi-tagged argument count, may be zero.
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchLink(&array_label);
+ __ BranchLink(*StubCode::AllocateArray_entry());
// R0: newly allocated array.
// R2: smi-tagged argument count, may be zero (was preserved by the stub).
__ Push(R0); // Array is in R0 and on top of stack.
@@ -628,20 +604,15 @@
// R1: array element type (either NULL or an instantiated type).
// R2: array length as Smi (must be preserved).
// The newly allocated object is returned in R0.
-void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler,
- uword* entry_patch_offset, uword* patch_code_pc_offset) {
- *entry_patch_offset = assembler->CodeSize();
+void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
Label slow_case;
- Isolate* isolate = Isolate::Current();
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
__ MoveRegister(R3, R2); // Array length.
- const Class& cls = Class::Handle(isolate->object_store()->array_class());
- ASSERT(!cls.IsNull());
// Check that length is a positive Smi.
__ tst(R3, Operand(kSmiTagMask));
- if (FLAG_use_slow_path || cls.trace_allocation()) {
+ if (FLAG_use_slow_path) {
__ b(&slow_case);
} else {
__ b(&slow_case, NE);
@@ -655,6 +626,10 @@
__ CompareImmediate(R3, max_len);
__ b(&slow_case, GT);
+ const intptr_t cid = kArrayCid;
+ __ MaybeTraceAllocation(cid, R4, &slow_case,
+ /* inline_isolate = */ false);
+
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ LoadImmediate(R9, fixed_size);
__ add(R9, R9, Operand(R3, LSL, 1)); // R3 is a Smi.
@@ -662,12 +637,11 @@
__ bic(R9, R9, Operand(kObjectAlignment - 1));
// R9: Allocation size.
-
- Heap* heap = isolate->heap();
- const intptr_t cid = kArrayCid;
Heap::Space space = Heap::SpaceForAllocation(cid);
- __ LoadImmediate(R6, heap->TopAddress(space));
- __ ldr(R0, Address(R6, 0)); // Potential new object start.
+ __ LoadIsolate(R6);
+ __ ldr(R6, Address(R6, Isolate::heap_offset()));
+ // Potential new object start.
+ __ ldr(R0, Address(R6, Heap::TopOffset(space)));
__ adds(R7, R0, Operand(R9)); // Potential next object start.
__ b(&slow_case, CS); // Branch if unsigned overflow.
@@ -675,15 +649,14 @@
// R0: potential new object start.
// R7: potential next object start.
// R9: allocation size.
- __ LoadImmediate(R3, heap->EndAddress(space));
- __ ldr(R3, Address(R3, 0));
+ __ ldr(R3, Address(R6, Heap::EndOffset(space)));
__ cmp(R7, Operand(R3));
__ b(&slow_case, CS);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ LoadAllocationStatsAddress(R3, cid);
- __ str(R7, Address(R6, 0));
+ __ LoadAllocationStatsAddress(R3, cid, /* inline_isolate = */ false);
+ __ str(R7, Address(R6, Heap::TopOffset(space)));
__ add(R0, R0, Operand(kHeapObjectTag));
// Initialize the tags.
@@ -749,9 +722,6 @@
__ mov(R0, Operand(IP));
__ LeaveStubFrame();
__ Ret();
- *patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->FixAllocateArrayStubTargetLabel());
}
@@ -863,6 +833,7 @@
}
// Restore CPU registers.
__ PopList(kAbiPreservedCpuRegs);
+ __ set_constant_pool_allowed(false);
// Restore the frame pointer and return.
__ LeaveFrame((1 << FP) | (1 << LR));
@@ -1091,27 +1062,26 @@
Label slow_case;
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
- Heap* heap = Isolate::Current()->heap();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
- __ LoadImmediate(R5, heap->TopAddress(space));
- __ ldr(R0, Address(R5, 0));
+ __ ldr(R5, Address(THR, Thread::heap_offset()));
+ __ ldr(R0, Address(R5, Heap::TopOffset(space)));
__ AddImmediate(R1, R0, instance_size);
// Check if the allocation fits into the remaining space.
// R0: potential new object start.
// R1: potential next object start.
- __ LoadImmediate(IP, heap->EndAddress(space));
- __ ldr(IP, Address(IP, 0));
+ // R5: heap.
+ __ ldr(IP, Address(R5, Heap::EndOffset(space)));
__ cmp(R1, Operand(IP));
if (FLAG_use_slow_path) {
__ b(&slow_case);
} else {
__ b(&slow_case, CS); // Unsigned higher or equal.
}
- __ str(R1, Address(R5, 0));
+ __ str(R1, Address(R5, Heap::TopOffset(space)));
// Load the address of the allocation stats table. We split up the load
// and the increment so that the dependent load is not too nearby.
- __ LoadAllocationStatsAddress(R5, cls.id());
+ __ LoadAllocationStatsAddress(R5, cls.id(), /* inline_isolate = */ false);
// R0: new object start.
// R1: next object start.
@@ -1202,8 +1172,7 @@
__ LeaveStubFrame();
__ Ret();
*patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->FixAllocationStubTargetLabel());
+ __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry());
}
@@ -1963,11 +1932,10 @@
// Return Zero condition flag set if equal.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
- const Register left,
- const Register right,
- const Register temp,
- const Register unused) {
+static void GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ tst(left, Operand(kSmiTagMask));
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 007bfe9..b3bd552 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -52,13 +52,13 @@
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(R8, R28, Isolate::vm_tag_offset(), kNoPP);
- __ CompareImmediate(R8, VMTag::kDartTagId, kNoPP);
+ __ LoadFromOffset(R8, R28, Isolate::vm_tag_offset());
+ __ CompareImmediate(R8, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
@@ -66,7 +66,7 @@
#endif
// Mark that the isolate is executing VM code.
- __ StoreToOffset(R5, R28, Isolate::vm_tag_offset(), kNoPP);
+ __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
// Reserve space for arguments and align frame before entering C++ world.
// NativeArguments are passed in registers.
@@ -91,15 +91,15 @@
__ add(R2, ZR, Operand(R4, LSL, 3));
__ add(R2, FP, Operand(R2)); // Compute argv.
// Set argv in NativeArguments.
- __ AddImmediate(R2, R2, exitframe_last_param_slot_from_fp * kWordSize, kNoPP);
+ __ AddImmediate(R2, R2, exitframe_last_param_slot_from_fp * kWordSize);
ASSERT(retval_offset == 3 * kWordSize);
- __ AddImmediate(R3, R2, kWordSize, kNoPP);
+ __ AddImmediate(R3, R2, kWordSize);
- __ StoreToOffset(R0, SP, thread_offset, kNoPP);
- __ StoreToOffset(R1, SP, argc_tag_offset, kNoPP);
- __ StoreToOffset(R2, SP, argv_offset, kNoPP);
- __ StoreToOffset(R3, SP, retval_offset, kNoPP);
+ __ StoreToOffset(R0, SP, thread_offset);
+ __ StoreToOffset(R1, SP, argc_tag_offset);
+ __ StoreToOffset(R2, SP, argv_offset);
+ __ StoreToOffset(R3, SP, retval_offset);
__ mov(R0, SP); // Pass the pointer to the NativeArguments.
// We are entering runtime code, so the C stack pointer must be restored from
@@ -117,11 +117,11 @@
// Retval is next to 1st argument.
// Mark that the isolate is executing Dart code.
- __ LoadImmediate(R2, VMTag::kDartTagId, kNoPP);
- __ StoreToOffset(R2, R28, Isolate::vm_tag_offset(), kNoPP);
+ __ LoadImmediate(R2, VMTag::kDartTagId);
+ __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
// Reset exit frame information in Isolate structure.
- __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
__ LeaveStubFrame();
__ ret();
@@ -152,13 +152,13 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset(), kNoPP);
- __ CompareImmediate(R6, VMTag::kDartTagId, kNoPP);
+ __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset());
+ __ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
@@ -166,7 +166,7 @@
#endif
// Mark that the isolate is executing Native code.
- __ StoreToOffset(R5, R28, Isolate::vm_tag_offset(), kNoPP);
+ __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -190,15 +190,15 @@
// Set retval in NativeArgs.
ASSERT(retval_offset == 3 * kWordSize);
- __ AddImmediate(R3, FP, 2 * kWordSize, kNoPP);
+ __ AddImmediate(R3, FP, 2 * kWordSize);
// Passing the structure by value as in runtime calls would require changing
// Dart API for native functions.
// For now, space is reserved on the stack and we pass a pointer to it.
- __ StoreToOffset(R0, SP, thread_offset, kNoPP);
- __ StoreToOffset(R1, SP, argc_tag_offset, kNoPP);
- __ StoreToOffset(R2, SP, argv_offset, kNoPP);
- __ StoreToOffset(R3, SP, retval_offset, kNoPP);
+ __ StoreToOffset(R0, SP, thread_offset);
+ __ StoreToOffset(R1, SP, argc_tag_offset);
+ __ StoreToOffset(R2, SP, argv_offset);
+ __ StoreToOffset(R3, SP, retval_offset);
__ mov(R0, SP); // Pass the pointer to the NativeArguments.
// We are entering runtime code, so the C stack pointer must be restored from
@@ -213,10 +213,10 @@
uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper);
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments);
- __ LoadImmediate(R2, entry, kNoPP);
+ __ LoadImmediate(R2, entry);
__ blr(R2);
#else
- __ BranchLink(&NativeEntry::NativeCallWrapperLabel(), kNoPP);
+ __ BranchLink(&NativeEntry::NativeCallWrapperLabel());
#endif
// Restore SP and CSP.
@@ -224,11 +224,11 @@
__ mov(CSP, R26);
// Mark that the isolate is executing Dart code.
- __ LoadImmediate(R2, VMTag::kDartTagId, kNoPP);
- __ StoreToOffset(R2, R28, Isolate::vm_tag_offset(), kNoPP);
+ __ LoadImmediate(R2, VMTag::kDartTagId);
+ __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
// Reset exit frame information in Isolate structure.
- __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
__ LeaveStubFrame();
__ ret();
@@ -254,13 +254,13 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
#if defined(DEBUG)
{ Label ok;
// Check that we are always entering from Dart code.
- __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset(), kNoPP);
- __ CompareImmediate(R6, VMTag::kDartTagId, kNoPP);
+ __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset());
+ __ CompareImmediate(R6, VMTag::kDartTagId);
__ b(&ok, EQ);
__ Stop("Not coming from Dart code.");
__ Bind(&ok);
@@ -268,7 +268,7 @@
#endif
// Mark that the isolate is executing Native code.
- __ StoreToOffset(R5, R28, Isolate::vm_tag_offset(), kNoPP);
+ __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
@@ -292,15 +292,15 @@
// Set retval in NativeArgs.
ASSERT(retval_offset == 3 * kWordSize);
- __ AddImmediate(R3, FP, 2 * kWordSize, kNoPP);
+ __ AddImmediate(R3, FP, 2 * kWordSize);
// Passing the structure by value as in runtime calls would require changing
// Dart API for native functions.
// For now, space is reserved on the stack and we pass a pointer to it.
- __ StoreToOffset(R0, SP, thread_offset, kNoPP);
- __ StoreToOffset(R1, SP, argc_tag_offset, kNoPP);
- __ StoreToOffset(R2, SP, argv_offset, kNoPP);
- __ StoreToOffset(R3, SP, retval_offset, kNoPP);
+ __ StoreToOffset(R0, SP, thread_offset);
+ __ StoreToOffset(R1, SP, argc_tag_offset);
+ __ StoreToOffset(R2, SP, argv_offset);
+ __ StoreToOffset(R3, SP, retval_offset);
__ mov(R0, SP); // Pass the pointer to the NativeArguments.
// We are entering runtime code, so the C stack pointer must be restored from
@@ -317,11 +317,11 @@
__ mov(CSP, R26);
// Mark that the isolate is executing Dart code.
- __ LoadImmediate(R2, VMTag::kDartTagId, kNoPP);
- __ StoreToOffset(R2, R28, Isolate::vm_tag_offset(), kNoPP);
+ __ LoadImmediate(R2, VMTag::kDartTagId);
+ __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
// Reset exit frame information in Isolate structure.
- __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
__ LeaveStubFrame();
__ ret();
@@ -336,7 +336,7 @@
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
__ Push(R4);
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
// Get Code object result and restore arguments descriptor array.
__ Pop(R0);
@@ -344,8 +344,8 @@
// Remove the stub frame.
__ LeaveStubFrame();
// Jump to the dart function.
- __ LoadFieldFromOffset(R0, R0, Code::instructions_offset(), kNoPP);
- __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ __ LoadFieldFromOffset(R0, R0, Code::instructions_offset());
+ __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R0);
}
@@ -359,7 +359,7 @@
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
__ Push(R4);
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ CallRuntime(kFixCallersTargetRuntimeEntry, 0);
// Get Code object result and restore arguments descriptor array.
__ Pop(R0);
@@ -367,8 +367,8 @@
// Remove the stub frame.
__ LeaveStubFrame();
// Jump to the dart function.
- __ LoadFieldFromOffset(R0, R0, Code::instructions_offset(), kNoPP);
- __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ __ LoadFieldFromOffset(R0, R0, Code::instructions_offset());
+ __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R0);
}
@@ -378,39 +378,15 @@
void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) {
__ EnterStubFrame();
// Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
// Get Code object result.
__ Pop(R0);
// Remove the stub frame.
__ LeaveStubFrame();
// Jump to the dart function.
- __ LoadFieldFromOffset(R0, R0, Code::instructions_offset(), kNoPP);
- __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
- __ br(R0);
-}
-
-
-// Called from array allocate instruction when the allocation stub has been
-// disabled.
-// R1: element type (preserved).
-// R2: length (preserved).
-void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) {
- __ EnterStubFrame();
- // Setup space on stack for return value and preserve length, element type.
- __ Push(R1);
- __ Push(R2);
- __ PushObject(Object::null_object(), PP);
- __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
- // Get Code object result and restore length, element type.
- __ Pop(R0);
- __ Pop(R2);
- __ Pop(R1);
- // Remove the stub frame.
- __ LeaveStubFrame();
- // Jump to the dart function.
- __ LoadFieldFromOffset(R0, R0, Code::instructions_offset(), kNoPP);
- __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ __ LoadFieldFromOffset(R0, R0, Code::instructions_offset());
+ __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R0);
}
@@ -419,20 +395,17 @@
// R2: smi-tagged argument count, may be zero.
// FP[kParamEndSlotFromFp + 1]: last argument.
static void PushArgumentsArray(Assembler* assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
// Allocate array to store arguments of caller.
- __ LoadObject(R1, Object::null_object(), PP);
+ __ LoadObject(R1, Object::null_object());
// R1: null element type for raw Array.
// R2: smi-tagged argument count, may be zero.
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchLink(&array_label, PP);
+ __ BranchLink(*StubCode::AllocateArray_entry());
// R0: newly allocated array.
// R2: smi-tagged argument count, may be zero (was preserved by the stub).
__ Push(R0); // Array is in R0 and on top of stack.
__ add(R1, FP, Operand(R2, LSL, 2));
- __ AddImmediate(R1, R1, kParamEndSlotFromFp * kWordSize, PP);
- __ AddImmediate(R3, R0, Array::data_offset() - kHeapObjectTag, PP);
+ __ AddImmediate(R1, R1, kParamEndSlotFromFp * kWordSize);
+ __ AddImmediate(R3, R0, Array::data_offset() - kHeapObjectTag);
// R1: address of first argument on stack.
// R3: address of first argument in array.
@@ -441,9 +414,9 @@
__ b(&loop_exit, LE);
__ Bind(&loop);
__ ldr(R7, Address(R1));
- __ AddImmediate(R1, R1, -kWordSize, PP);
- __ AddImmediate(R3, R3, kWordSize, PP);
- __ AddImmediateSetFlags(R2, R2, -Smi::RawValue(1), PP);
+ __ AddImmediate(R1, R1, -kWordSize);
+ __ AddImmediate(R3, R3, kWordSize);
+ __ AddImmediateSetFlags(R2, R2, -Smi::RawValue(1));
__ str(R7, Address(R3, -kWordSize));
__ b(&loop, GE);
__ Bind(&loop_exit);
@@ -513,7 +486,7 @@
if (preserve_result) {
// Restore result into R1 temporarily.
- __ LoadFromOffset(R1, FP, saved_result_slot_from_fp * kWordSize, kNoPP);
+ __ LoadFromOffset(R1, FP, saved_result_slot_from_fp * kWordSize);
}
// There is a Dart Frame on the stack. We must restore PP and leave frame.
@@ -533,7 +506,7 @@
__ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1);
if (preserve_result) {
// Restore result into R1.
- __ LoadFromOffset(R1, FP, kFirstLocalSlotFromFp * kWordSize, kNoPP);
+ __ LoadFromOffset(R1, FP, kFirstLocalSlotFromFp * kWordSize);
}
// Code above cannot cause GC.
// There is a Dart Frame on the stack. We must restore PP and leave frame.
@@ -568,7 +541,7 @@
void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) {
// Correct return address to point just after the call that is being
// deoptimized.
- __ AddImmediate(LR, LR, -CallPattern::kLengthInBytes, kNoPP);
+ __ AddImmediate(LR, LR, -CallPattern::kLengthInBytes);
GenerateDeoptimizationSequence(assembler, true); // Preserve R0.
}
@@ -583,15 +556,15 @@
__ Comment("NoSuchMethodDispatch");
// When lazily generated invocation dispatchers are disabled, the
// miss-handler may return null.
- __ CompareObject(R0, Object::null_object(), PP);
+ __ CompareObject(R0, Object::null_object());
__ b(call_target_function, NE);
__ EnterStubFrame();
// Load the receiver.
- __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset(), kNoPP);
+ __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset());
__ add(TMP, FP, Operand(R2, LSL, 2)); // R2 is Smi.
- __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize, kNoPP);
- __ PushObject(Object::null_object(), PP);
+ __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize);
+ __ PushObject(Object::null_object());
__ Push(R6);
__ Push(R5);
__ Push(R4);
@@ -610,9 +583,9 @@
__ EnterStubFrame();
// Load the receiver.
- __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset(), kNoPP);
+ __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset());
__ add(TMP, FP, Operand(R2, LSL, 2)); // R2 is Smi.
- __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize, kNoPP);
+ __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize);
// Preserve IC data and arguments descriptor.
__ Push(R5);
@@ -622,7 +595,7 @@
// Push the receiver.
// Push IC data object.
// Push arguments descriptor array.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ Push(R6);
__ Push(R5);
__ Push(R4);
@@ -644,8 +617,8 @@
}
// Tail-call to target function.
- __ LoadFieldFromOffset(R2, R0, Function::instructions_offset(), kNoPP);
- __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP);
+ __ LoadFieldFromOffset(R2, R0, Function::instructions_offset());
+ __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R2);
}
@@ -657,19 +630,14 @@
// R1: array element type (either NULL or an instantiated type).
// NOTE: R2 cannot be clobbered here as the caller relies on it being saved.
// The newly allocated object is returned in R0.
-void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler,
- uword* entry_patch_offset, uword* patch_code_pc_offset) {
- *entry_patch_offset = assembler->CodeSize();
+void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
Label slow_case;
- Isolate* isolate = Isolate::Current();
- const Class& cls = Class::Handle(isolate->object_store()->array_class());
- ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
// Assert that length is a Smi.
__ tsti(R2, Immediate(kSmiTagMask));
- if (FLAG_use_slow_path || cls.trace_allocation()) {
+ if (FLAG_use_slow_path) {
__ b(&slow_case);
} else {
__ b(&slow_case, NE);
@@ -677,24 +645,28 @@
__ cmp(R2, Operand(0));
__ b(&slow_case, LT);
- Heap* heap = isolate->heap();
+ // Check for maximum allowed length.
+ const intptr_t max_len =
+ reinterpret_cast<intptr_t>(Smi::New(Array::kMaxElements));
+ __ CompareImmediate(R2, max_len);
+ __ b(&slow_case, GT);
+
const intptr_t cid = kArrayCid;
+ __ MaybeTraceAllocation(kArrayCid, R4, &slow_case,
+ /* inline_isolate = */ false);
+
Heap::Space space = Heap::SpaceForAllocation(cid);
- const uword top_address = heap->TopAddress(space);
- __ LoadImmediate(R8, top_address, kNoPP);
- const uword end_address = heap->EndAddress(space);
- ASSERT(top_address < end_address);
- const uword top_offset = 0;
- const uword end_offset = end_address - top_address;
+ __ LoadIsolate(R8);
+ __ ldr(R8, Address(R8, Isolate::heap_offset()));
// Calculate and align allocation size.
// Load new object start and calculate next object start.
// R1: array element type.
// R2: array length as Smi.
- // R8: points to new space object.
- __ LoadFromOffset(R0, R8, top_offset, kNoPP);
+ // R8: heap.
+ __ LoadFromOffset(R0, R8, Heap::TopOffset(space));
intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
- __ LoadImmediate(R3, fixed_size, kNoPP);
+ __ LoadImmediate(R3, fixed_size);
__ add(R3, R3, Operand(R2, LSL, 2)); // R2 is Smi.
ASSERT(kSmiTagShift == 1);
__ andi(R3, R3, Immediate(~(kObjectAlignment - 1)));
@@ -709,8 +681,8 @@
// R2: array length as Smi.
// R3: array size.
// R7: potential next object start.
- // R8: points to new space object.
- __ LoadFromOffset(TMP, R8, end_offset, kNoPP);
+ // R8: heap.
+ __ LoadFromOffset(TMP, R8, Heap::EndOffset(space));
__ CompareRegisters(R7, TMP);
__ b(&slow_case, CS); // Branch if unsigned higher or equal.
@@ -719,10 +691,11 @@
// R0: potential new object start.
// R3: array size.
// R7: potential next object start.
- // R8: Points to new space object.
- __ StoreToOffset(R7, R8, top_offset, kNoPP);
+ // R8: heap.
+ __ StoreToOffset(R7, R8, Heap::TopOffset(space));
__ add(R0, R0, Operand(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, R3, kNoPP, space);
+ __ UpdateAllocationStatsWithSize(cid, R3, space,
+ /* inline_isolate = */ false);
// R0: new object start as a tagged pointer.
// R1: array element type.
@@ -732,10 +705,10 @@
// Store the type argument field.
__ StoreIntoObjectOffsetNoBarrier(
- R0, Array::type_arguments_offset(), R1, PP);
+ R0, Array::type_arguments_offset(), R1);
// Set the length field.
- __ StoreIntoObjectOffsetNoBarrier(R0, Array::length_offset(), R2, PP);
+ __ StoreIntoObjectOffsetNoBarrier(R0, Array::length_offset(), R2);
// Calculate the size tag.
// R0: new object start as a tagged pointer.
@@ -743,32 +716,32 @@
// R3: array size.
// R7: new object end address.
const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2;
- __ CompareImmediate(R3, RawObject::SizeTag::kMaxSizeTag, kNoPP);
+ __ CompareImmediate(R3, RawObject::SizeTag::kMaxSizeTag);
// If no size tag overflow, shift R1 left, else set R1 to zero.
__ LslImmediate(TMP, R3, shift);
__ csel(R1, TMP, R1, LS);
__ csel(R1, ZR, R1, HI);
// Get the class index and insert it into the tags.
- __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid), kNoPP);
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid));
__ orr(R1, R1, Operand(TMP));
- __ StoreFieldToOffset(R1, R0, Array::tags_offset(), kNoPP);
+ __ StoreFieldToOffset(R1, R0, Array::tags_offset());
// Initialize all array elements to raw_null.
// R0: new object start as a tagged pointer.
// R7: new object end address.
// R2: array length as Smi.
- __ AddImmediate(R1, R0, Array::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R1, R0, Array::data_offset() - kHeapObjectTag);
// R1: iterator which initially points to the start of the variable
// data area to be initialized.
- __ LoadObject(TMP, Object::null_object(), PP);
+ __ LoadObject(TMP, Object::null_object());
Label loop, done;
__ Bind(&loop);
// TODO(cshapiro): StoreIntoObjectNoBarrier
__ CompareRegisters(R1, R7);
__ b(&done, CS);
__ str(TMP, Address(R1)); // Store if unsigned lower.
- __ AddImmediate(R1, R1, kWordSize, kNoPP);
+ __ AddImmediate(R1, R1, kWordSize);
__ b(&loop); // Loop until R1 == R7.
__ Bind(&done);
@@ -785,7 +758,7 @@
__ EnterStubFrame();
// Setup space on stack for return value.
// Push array length as Smi and element type.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ Push(R2);
__ Push(R1);
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
@@ -795,9 +768,6 @@
__ Pop(R0);
__ LeaveStubFrame();
__ ret();
- *patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->FixAllocateArrayStubTargetLabel());
}
@@ -834,7 +804,7 @@
// We now load the pool pointer(PP) as we are about to invoke dart code and we
// could potentially invoke some intrinsic functions which need the PP to be
// set up.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
// Set up THR, which caches the current thread in Dart code.
if (THR != R3) {
@@ -844,41 +814,41 @@
__ LoadIsolate(R5);
// Save the current VMTag on the stack.
- __ LoadFromOffset(R4, R5, Isolate::vm_tag_offset(), PP);
+ __ LoadFromOffset(R4, R5, Isolate::vm_tag_offset());
__ Push(R4);
// Mark that the isolate is executing Dart code.
- __ LoadImmediate(R6, VMTag::kDartTagId, PP);
- __ StoreToOffset(R6, R5, Isolate::vm_tag_offset(), PP);
+ __ LoadImmediate(R6, VMTag::kDartTagId);
+ __ StoreToOffset(R6, R5, Isolate::vm_tag_offset());
// Save top resource and top exit frame info. Use R6 as a temporary register.
// StackFrameIterator reads the top exit frame info saved in this frame.
- __ LoadFromOffset(R6, THR, Thread::top_resource_offset(), PP);
- __ StoreToOffset(ZR, THR, Thread::top_resource_offset(), PP);
+ __ LoadFromOffset(R6, THR, Thread::top_resource_offset());
+ __ StoreToOffset(ZR, THR, Thread::top_resource_offset());
__ Push(R6);
- __ LoadFromOffset(R6, THR, Thread::top_exit_frame_info_offset(), PP);
- __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), PP);
+ __ LoadFromOffset(R6, THR, Thread::top_exit_frame_info_offset());
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
// kExitLinkSlotFromEntryFp must be kept in sync with the code below.
ASSERT(kExitLinkSlotFromEntryFp == -21);
__ Push(R6);
// Load arguments descriptor array into R4, which is passed to Dart code.
- __ LoadFromOffset(R4, R1, VMHandles::kOffsetOfRawPtrInHandle, PP);
+ __ LoadFromOffset(R4, R1, VMHandles::kOffsetOfRawPtrInHandle);
// Load number of arguments into S5.
- __ LoadFieldFromOffset(R5, R4, ArgumentsDescriptor::count_offset(), PP);
+ __ LoadFieldFromOffset(R5, R4, ArgumentsDescriptor::count_offset());
__ SmiUntag(R5);
// Compute address of 'arguments array' data area into R2.
- __ LoadFromOffset(R2, R2, VMHandles::kOffsetOfRawPtrInHandle, PP);
- __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag, PP);
+ __ LoadFromOffset(R2, R2, VMHandles::kOffsetOfRawPtrInHandle);
+ __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag);
// Set up arguments for the Dart call.
Label push_arguments;
Label done_push_arguments;
__ cmp(R5, Operand(0));
__ b(&done_push_arguments, EQ); // check if there are arguments.
- __ LoadImmediate(R1, 0, PP);
+ __ LoadImmediate(R1, 0);
__ Bind(&push_arguments);
__ ldr(R3, Address(R2));
__ Push(R3);
@@ -893,23 +863,23 @@
__ Comment("InvokeDartCodeStub return");
// Restore constant pool pointer after return.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
// Get rid of arguments pushed on the stack.
- __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize, PP);
+ __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
__ LoadIsolate(R28);
// Restore the saved top exit frame info and top resource back into the
// Isolate structure. Uses R6 as a temporary register for this.
__ Pop(R6);
- __ StoreToOffset(R6, THR, Thread::top_exit_frame_info_offset(), PP);
+ __ StoreToOffset(R6, THR, Thread::top_exit_frame_info_offset());
__ Pop(R6);
- __ StoreToOffset(R6, THR, Thread::top_resource_offset(), PP);
+ __ StoreToOffset(R6, THR, Thread::top_resource_offset());
// Restore the current VMTag from the stack.
__ Pop(R4);
- __ StoreToOffset(R4, R28, Isolate::vm_tag_offset(), PP);
+ __ StoreToOffset(R4, R28, Isolate::vm_tag_offset());
// Restore the bottom 64-bits of callee-saved V registers.
for (int i = kAbiLastPreservedFpuReg; i >= kAbiFirstPreservedFpuReg; i--) {
@@ -926,6 +896,7 @@
// using it as the stack pointer.
__ ldr(r, Address(SP, 1 * kWordSize, Address::PostIndex));
}
+ __ set_constant_pool_allowed(false);
// Restore the frame pointer and C stack pointer and return.
__ LeaveFrame();
@@ -945,7 +916,7 @@
// First compute the rounded instance size.
// R1: number of context variables.
intptr_t fixed_size = sizeof(RawContext) + kObjectAlignment - 1;
- __ LoadImmediate(R2, fixed_size, kNoPP);
+ __ LoadImmediate(R2, fixed_size);
__ add(R2, R2, Operand(R1, LSL, 3));
ASSERT(kSmiTagShift == 1);
__ andi(R2, R2, Immediate(~(kObjectAlignment - 1)));
@@ -982,7 +953,7 @@
// R5: heap.
__ str(R3, Address(R5, Heap::TopOffset(space)));
__ add(R0, R0, Operand(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, R2, kNoPP, space,
+ __ UpdateAllocationStatsWithSize(cid, R2, space,
/* inline_isolate = */ false);
// Calculate the size tag.
@@ -990,7 +961,7 @@
// R1: number of context variables.
// R2: object size.
const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2;
- __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag, kNoPP);
+ __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
// If no size tag overflow, shift R2 left, else set R2 to zero.
__ LslImmediate(TMP, R2, shift);
__ csel(R2, TMP, R2, LS);
@@ -998,20 +969,20 @@
// Get the class index and insert it into the tags.
// R2: size and bit tags.
- __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid), kNoPP);
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid));
__ orr(R2, R2, Operand(TMP));
- __ StoreFieldToOffset(R2, R0, Context::tags_offset(), kNoPP);
+ __ StoreFieldToOffset(R2, R0, Context::tags_offset());
// Setup up number of context variables field.
// R0: new object.
// R1: number of context variables as integer value (not object).
- __ StoreFieldToOffset(R1, R0, Context::num_variables_offset(), kNoPP);
+ __ StoreFieldToOffset(R1, R0, Context::num_variables_offset());
// Setup the parent field.
// R0: new object.
// R1: number of context variables.
- __ LoadObject(R2, Object::null_object(), PP);
- __ StoreFieldToOffset(R2, R0, Context::parent_offset(), kNoPP);
+ __ LoadObject(R2, Object::null_object());
+ __ StoreFieldToOffset(R2, R0, Context::parent_offset());
// Initialize the context variables.
// R0: new object.
@@ -1019,7 +990,7 @@
// R2: raw null.
Label loop, done;
__ AddImmediate(
- R3, R0, Context::variable_offset(0) - kHeapObjectTag, kNoPP);
+ R3, R0, Context::variable_offset(0) - kHeapObjectTag);
__ Bind(&loop);
__ subs(R1, R1, Operand(1));
__ b(&done, MI);
@@ -1038,7 +1009,7 @@
__ EnterStubFrame();
// Setup space on stack for return value.
__ SmiTag(R1);
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ Push(R1);
__ CallRuntime(kAllocateContextRuntimeEntry, 1); // Allocate context.
__ Drop(1); // Pop number of context variables argument.
@@ -1059,7 +1030,7 @@
Label add_to_buffer;
// Check whether this object has already been remembered. Skip adding to the
// store buffer if the object is in the store buffer already.
- __ LoadFieldFromOffset(TMP, R0, Object::tags_offset(), kNoPP);
+ __ LoadFieldFromOffset(TMP, R0, Object::tags_offset());
__ tsti(TMP, Immediate(1 << RawObject::kRememberedBit));
__ b(&add_to_buffer, EQ);
__ ret();
@@ -1071,24 +1042,22 @@
__ Push(R3);
__ orri(R2, TMP, Immediate(1 << RawObject::kRememberedBit));
- __ StoreFieldToOffset(R2, R0, Object::tags_offset(), kNoPP);
+ __ StoreFieldToOffset(R2, R0, Object::tags_offset());
// Load the StoreBuffer block out of the thread. Then load top_ out of the
// StoreBufferBlock and add the address to the pointers_.
- __ LoadFromOffset(R1, THR, Thread::store_buffer_block_offset(), kNoPP);
- __ LoadFromOffset(R2, R1, StoreBufferBlock::top_offset(),
- kNoPP, kUnsignedWord);
+ __ LoadFromOffset(R1, THR, Thread::store_buffer_block_offset());
+ __ LoadFromOffset(R2, R1, StoreBufferBlock::top_offset(), kUnsignedWord);
__ add(R3, R1, Operand(R2, LSL, 3));
- __ StoreToOffset(R0, R3, StoreBufferBlock::pointers_offset(), kNoPP);
+ __ StoreToOffset(R0, R3, StoreBufferBlock::pointers_offset());
// Increment top_ and check for overflow.
// R2: top_.
// R1: StoreBufferBlock.
Label L;
__ add(R2, R2, Operand(1));
- __ StoreToOffset(R2, R1, StoreBufferBlock::top_offset(),
- kNoPP, kUnsignedWord);
- __ CompareImmediate(R2, StoreBufferBlock::kSize, kNoPP);
+ __ StoreToOffset(R2, R1, StoreBufferBlock::top_offset(), kUnsignedWord);
+ __ CompareImmediate(R2, StoreBufferBlock::kSize);
// Restore values.
__ Pop(R3);
__ Pop(R2);
@@ -1137,24 +1106,23 @@
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
// R1: instantiated type arguments (if is_cls_parameterized).
- Heap* heap = Isolate::Current()->heap();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
- __ LoadImmediate(R5, heap->TopAddress(space), kNoPP);
- __ ldr(R2, Address(R5));
- __ AddImmediate(R3, R2, instance_size, kNoPP);
+ __ ldr(R5, Address(THR, Thread::heap_offset()));
+ __ ldr(R2, Address(R5, Heap::TopOffset(space)));
+ __ AddImmediate(R3, R2, instance_size);
// Check if the allocation fits into the remaining space.
// R2: potential new object start.
// R3: potential next object start.
- __ LoadImmediate(TMP, heap->EndAddress(space), kNoPP);
- __ ldr(TMP, Address(TMP));
+ // R5: heap.
+ __ ldr(TMP, Address(R5, Heap::EndOffset(space)));
__ CompareRegisters(R3, TMP);
if (FLAG_use_slow_path) {
__ b(&slow_case);
} else {
__ b(&slow_case, CS); // Unsigned higher or equal.
}
- __ str(R3, Address(R5));
- __ UpdateAllocationStats(cls.id(), kNoPP, space);
+ __ str(R3, Address(R5, Heap::TopOffset(space)));
+ __ UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
// R2: new object start.
// R3: next object start.
@@ -1164,11 +1132,11 @@
tags = RawObject::SizeTag::update(instance_size, tags);
ASSERT(cls.id() != kIllegalCid);
tags = RawObject::ClassIdTag::update(cls.id(), tags);
- __ LoadImmediate(R0, tags, kNoPP);
- __ StoreToOffset(R0, R2, Instance::tags_offset(), kNoPP);
+ __ LoadImmediate(R0, tags);
+ __ StoreToOffset(R0, R2, Instance::tags_offset());
// Initialize the remaining words of the object.
- __ LoadObject(R0, Object::null_object(), PP);
+ __ LoadObject(R0, Object::null_object());
// R0: raw null.
// R2: new object start.
@@ -1181,10 +1149,10 @@
for (intptr_t current_offset = Instance::NextFieldOffset();
current_offset < instance_size;
current_offset += kWordSize) {
- __ StoreToOffset(R0, R2, current_offset, kNoPP);
+ __ StoreToOffset(R0, R2, current_offset);
}
} else {
- __ AddImmediate(R4, R2, Instance::NextFieldOffset(), kNoPP);
+ __ AddImmediate(R4, R2, Instance::NextFieldOffset());
// Loop until the whole object is initialized.
// R0: raw null.
// R2: new object.
@@ -1197,14 +1165,14 @@
__ CompareRegisters(R4, R3);
__ b(&done, CS);
__ str(R0, Address(R4));
- __ AddImmediate(R4, R4, kWordSize, kNoPP);
+ __ AddImmediate(R4, R4, kWordSize);
__ b(&init_loop);
__ Bind(&done);
}
if (is_cls_parameterized) {
// R1: new object type arguments.
// Set the type arguments in the new object.
- __ StoreToOffset(R1, R2, cls.type_arguments_field_offset(), kNoPP);
+ __ StoreToOffset(R1, R2, cls.type_arguments_field_offset());
}
// Done allocating and initializing the instance.
// R2: new object still missing its heap tag.
@@ -1220,14 +1188,14 @@
// calling into the runtime.
__ EnterStubFrame(); // Uses pool pointer to pass cls to runtime.
// Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
- __ PushObject(cls, PP); // Push class of object to be allocated.
+ __ PushObject(Object::null_object());
+ __ PushObject(cls); // Push class of object to be allocated.
if (is_cls_parameterized) {
// Push type arguments.
__ Push(R1);
} else {
// Push null type arguments.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
}
__ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object.
__ Drop(2); // Pop arguments.
@@ -1237,8 +1205,7 @@
__ LeaveStubFrame();
__ ret();
*patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->FixAllocationStubTargetLabel());
+ __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry());
}
@@ -1253,14 +1220,14 @@
__ EnterStubFrame();
// Load the receiver.
- __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset(), kNoPP);
+ __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset());
__ add(TMP, FP, Operand(R2, LSL, 2)); // R2 is Smi.
- __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize, kNoPP);
+ __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize);
// Push space for the return value.
// Push the receiver.
// Push arguments descriptor array.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ Push(R6);
__ Push(R4);
@@ -1294,10 +1261,10 @@
__ LeaveStubFrame();
}
__ LoadFieldFromOffset(
- R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord);
+ R7, func_reg, Function::usage_counter_offset(), kWord);
__ add(R7, R7, Operand(1));
__ StoreFieldToOffset(
- R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord);
+ R7, func_reg, Function::usage_counter_offset(), kWord);
}
@@ -1309,12 +1276,12 @@
Register func_reg = temp_reg;
ASSERT(temp_reg == R6);
__ Comment("Increment function counter");
- __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset(), kNoPP);
+ __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset());
__ LoadFieldFromOffset(
- R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord);
- __ AddImmediate(R7, R7, 1, kNoPP);
+ R7, func_reg, Function::usage_counter_offset(), kWord);
+ __ AddImmediate(R7, R7, 1);
__ StoreFieldToOffset(
- R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord);
+ R7, func_reg, Function::usage_counter_offset(), kWord);
}
}
@@ -1351,8 +1318,8 @@
}
case Token::kEQ: {
__ CompareRegisters(R0, R1);
- __ LoadObject(R0, Bool::True(), PP);
- __ LoadObject(R1, Bool::False(), PP);
+ __ LoadObject(R0, Bool::True());
+ __ LoadObject(R1, Bool::False());
__ csel(R0, R1, R0, NE);
break;
}
@@ -1366,19 +1333,19 @@
}
// R5: IC data object (preserved).
- __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP);
+ __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset());
// R6: ic_data_array with check entries: classes and target functions.
- __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag);
// R6: points directly to the first ic data array element.
#if defined(DEBUG)
// Check that first entry is for Smi/Smi.
Label error, ok;
const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid));
__ ldr(R1, Address(R6, 0));
- __ CompareImmediate(R1, imm_smi_cid, kNoPP);
+ __ CompareImmediate(R1, imm_smi_cid);
__ b(&error, NE);
__ ldr(R1, Address(R6, kWordSize));
- __ CompareImmediate(R1, imm_smi_cid, kNoPP);
+ __ CompareImmediate(R1, imm_smi_cid);
__ b(&ok, EQ);
__ Bind(&error);
__ Stop("Incorrect IC data");
@@ -1387,11 +1354,11 @@
if (FLAG_optimization_counter_threshold >= 0) {
const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
// Update counter.
- __ LoadFromOffset(R1, R6, count_offset, kNoPP);
+ __ LoadFromOffset(R1, R6, count_offset);
__ adds(R1, R1, Operand(Smi::RawValue(1)));
- __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue), kNoPP);
+ __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue));
__ csel(R1, R2, R1, VS); // Overflow.
- __ StoreToOffset(R1, R6, count_offset, kNoPP);
+ __ StoreToOffset(R1, R6, count_offset);
}
__ ret();
@@ -1421,10 +1388,10 @@
// Check that the IC data array has NumArgsTested() == num_args.
// 'NumArgsTested' is stored in the least significant bits of 'state_bits'.
__ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag,
- kNoPP, kUnsignedWord);
+ kUnsignedWord);
ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed.
__ andi(R6, R6, Immediate(ICData::NumArgsTestedMask()));
- __ CompareImmediate(R6, num_args, kNoPP);
+ __ CompareImmediate(R6, num_args);
__ b(&ok, EQ);
__ Stop("Incorrect stub for IC data");
__ Bind(&ok);
@@ -1436,7 +1403,7 @@
__ Comment("Check single stepping");
__ LoadIsolate(R6);
__ LoadFromOffset(
- R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
+ R6, R6, Isolate::single_step_offset(), kUnsignedByte);
__ CompareRegisters(R6, ZR);
__ b(&stepping, NE);
__ Bind(&done_stepping);
@@ -1465,18 +1432,18 @@
__ Comment("Extract ICData initial values and receiver cid");
// Load arguments descriptor into R4.
- __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset(), kNoPP);
+ __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset());
// Loop that checks if there is an IC data match.
Label loop, update, test, found;
// R5: IC data object (preserved).
- __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP);
+ __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset());
// R6: ic_data_array with check entries: classes and target functions.
- __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag);
// R6: points directly to the first ic data array element.
// Get the receiver's class ID (first read number of arguments from
// arguments descriptor array and then access the receiver from the stack).
- __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), kNoPP);
+ __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
__ SmiUntag(R7); // Untag so we can use the LSL 3 addressing mode.
__ sub(R7, R7, Operand(1));
@@ -1494,12 +1461,12 @@
for (int i = 0; i < num_args; i++) {
if (i > 0) {
// If not the first, load the next argument's class ID.
- __ AddImmediate(R0, R7, -i, kNoPP);
+ __ AddImmediate(R0, R7, -i);
// R0 <- [SP + (R0 << 3)]
__ ldr(R0, Address(SP, R0, UXTX, Address::Scaled));
__ LoadTaggedClassIdMayBeSmi(R0, R0);
// R0: next argument class ID (smi).
- __ LoadFromOffset(R1, R6, i * kWordSize, kNoPP);
+ __ LoadFromOffset(R1, R6, i * kWordSize);
// R1: next class ID to check (smi).
}
__ CompareRegisters(R0, R1); // Class id match?
@@ -1518,11 +1485,11 @@
}
const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
- __ AddImmediate(R6, R6, entry_size, kNoPP); // Next entry.
+ __ AddImmediate(R6, R6, entry_size); // Next entry.
__ ldr(R1, Address(R6)); // Next class ID.
__ Bind(&test);
- __ CompareImmediate(R1, Smi::RawValue(kIllegalCid), kNoPP); // Done?
+ __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done?
__ b(&loop, NE);
__ Comment("IC miss");
@@ -1539,10 +1506,10 @@
__ Push(R4); // Preserve arguments descriptor array.
__ Push(R5); // Preserve IC Data.
// Setup space on stack for the result (target code object).
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
// Push call arguments.
for (intptr_t i = 0; i < num_args; i++) {
- __ LoadFromOffset(TMP, R7, -i * kWordSize, kNoPP);
+ __ LoadFromOffset(TMP, R7, -i * kWordSize);
__ Push(TMP);
}
// Pass IC data object.
@@ -1568,23 +1535,23 @@
// R6: pointer to an IC data check group.
const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
- __ LoadFromOffset(R0, R6, target_offset, kNoPP);
+ __ LoadFromOffset(R0, R6, target_offset);
if (FLAG_optimization_counter_threshold >= 0) {
// Update counter.
- __ LoadFromOffset(R1, R6, count_offset, kNoPP);
+ __ LoadFromOffset(R1, R6, count_offset);
__ adds(R1, R1, Operand(Smi::RawValue(1)));
- __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue), kNoPP);
+ __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue));
__ csel(R1, R2, R1, VS); // Overflow.
- __ StoreToOffset(R1, R6, count_offset, kNoPP);
+ __ StoreToOffset(R1, R6, count_offset);
}
__ Comment("Call target");
__ Bind(&call_target_function);
// R0: target function.
- __ LoadFieldFromOffset(R2, R0, Function::instructions_offset(), kNoPP);
+ __ LoadFieldFromOffset(R2, R0, Function::instructions_offset());
__ AddImmediate(
- R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ R2, R2, Instructions::HeaderSize() - kHeapObjectTag);
if (range_collection_mode == kCollectRanges) {
__ ldr(R1, Address(SP, 0 * kWordSize));
if (num_args == 2) {
@@ -1715,10 +1682,10 @@
// Check that the IC data array has NumArgsTested() == 0.
// 'NumArgsTested' is stored in the least significant bits of 'state_bits'.
__ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag,
- kNoPP, kUnsignedWord);
+ kUnsignedWord);
ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed.
__ andi(R6, R6, Immediate(ICData::NumArgsTestedMask()));
- __ CompareImmediate(R6, 0, kNoPP);
+ __ CompareImmediate(R6, 0);
__ b(&ok, EQ);
__ Stop("Incorrect IC data for unoptimized static call");
__ Bind(&ok);
@@ -1730,40 +1697,40 @@
if (FLAG_support_debugger) {
__ LoadIsolate(R6);
__ LoadFromOffset(
- R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
- __ CompareImmediate(R6, 0, kNoPP);
+ R6, R6, Isolate::single_step_offset(), kUnsignedByte);
+ __ CompareImmediate(R6, 0);
__ b(&stepping, NE);
__ Bind(&done_stepping);
}
// R5: IC data object (preserved).
- __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP);
+ __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset());
// R6: ic_data_array with entries: target functions and count.
- __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP);
+ __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag);
// R6: points directly to the first ic data array element.
const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize;
const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
if (FLAG_optimization_counter_threshold >= 0) {
// Increment count for this call.
- __ LoadFromOffset(R1, R6, count_offset, kNoPP);
+ __ LoadFromOffset(R1, R6, count_offset);
__ adds(R1, R1, Operand(Smi::RawValue(1)));
- __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue), kNoPP);
+ __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue));
__ csel(R1, R2, R1, VS); // Overflow.
- __ StoreToOffset(R1, R6, count_offset, kNoPP);
+ __ StoreToOffset(R1, R6, count_offset);
}
// Load arguments descriptor into R4.
- __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset(), kNoPP);
+ __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset());
// Get function and call it, if possible.
- __ LoadFromOffset(R0, R6, target_offset, kNoPP);
- __ LoadFieldFromOffset(R2, R0, Function::instructions_offset(), kNoPP);
+ __ LoadFromOffset(R0, R6, target_offset);
+ __ LoadFieldFromOffset(R2, R0, Function::instructions_offset());
// R0: function.
// R2: target instructons.
__ AddImmediate(
- R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ R2, R2, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R2);
if (FLAG_support_debugger) {
@@ -1810,9 +1777,9 @@
__ Pop(R5); // Restore IC Data.
__ LeaveStubFrame();
- __ LoadFieldFromOffset(R2, R0, Function::instructions_offset(), kNoPP);
+ __ LoadFieldFromOffset(R2, R0, Function::instructions_offset());
__ AddImmediate(
- R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoPP);
+ R2, R2, Instructions::HeaderSize() - kHeapObjectTag);
__ br(R2);
}
@@ -1821,7 +1788,7 @@
void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) {
__ EnterStubFrame();
__ Push(R5);
- __ PushObject(Object::null_object(), PP); // Space for result.
+ __ PushObject(Object::null_object()); // Space for result.
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
__ Pop(R0);
__ Pop(R5);
@@ -1832,7 +1799,7 @@
void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) {
__ EnterStubFrame();
- __ PushObject(Object::null_object(), PP); // Space for result.
+ __ PushObject(Object::null_object()); // Space for result.
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
__ Pop(R0);
__ LeaveStubFrame();
@@ -1846,8 +1813,8 @@
Label stepping, done_stepping;
__ LoadIsolate(R1);
__ LoadFromOffset(
- R1, R1, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
- __ CompareImmediate(R1, 0, kNoPP);
+ R1, R1, Isolate::single_step_offset(), kUnsignedByte);
+ __ CompareImmediate(R1, 0);
__ b(&stepping, NE);
__ Bind(&done_stepping);
@@ -1871,26 +1838,26 @@
ASSERT((1 <= n) && (n <= 3));
if (n > 1) {
// Get instance type arguments.
- __ LoadClass(R3, R0, kNoPP);
+ __ LoadClass(R3, R0);
// Compute instance type arguments into R4.
Label has_no_type_arguments;
- __ LoadObject(R4, Object::null_object(), PP);
+ __ LoadObject(R4, Object::null_object());
__ LoadFieldFromOffset(R5, R3,
- Class::type_arguments_field_offset_in_words_offset(), kNoPP, kWord);
- __ CompareImmediate(R5, Class::kNoTypeArguments, kNoPP);
+ Class::type_arguments_field_offset_in_words_offset(), kWord);
+ __ CompareImmediate(R5, Class::kNoTypeArguments);
__ b(&has_no_type_arguments, EQ);
__ add(R5, R0, Operand(R5, LSL, 3));
- __ LoadFieldFromOffset(R4, R5, 0, kNoPP);
+ __ LoadFieldFromOffset(R4, R5, 0);
__ Bind(&has_no_type_arguments);
}
- __ LoadClassId(R3, R0, kNoPP);
+ __ LoadClassId(R3, R0);
// R0: instance.
// R1: instantiator type arguments or NULL.
// R2: SubtypeTestCache.
// R3: instance class id.
// R4: instance type arguments (null if none), used only if n > 1.
- __ LoadFieldFromOffset(R2, R2, SubtypeTestCache::cache_offset(), kNoPP);
- __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag, kNoPP);
+ __ LoadFieldFromOffset(R2, R2, SubtypeTestCache::cache_offset());
+ __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag);
Label loop, found, not_found, next_iteration;
// R2: entry start.
@@ -1899,8 +1866,8 @@
__ SmiTag(R3);
__ Bind(&loop);
__ LoadFromOffset(
- R5, R2, kWordSize * SubtypeTestCache::kInstanceClassId, kNoPP);
- __ CompareObject(R5, Object::null_object(), PP);
+ R5, R2, kWordSize * SubtypeTestCache::kInstanceClassId);
+ __ CompareObject(R5, Object::null_object());
__ b(¬_found, EQ);
__ CompareRegisters(R5, R3);
if (n == 1) {
@@ -1908,29 +1875,29 @@
} else {
__ b(&next_iteration, NE);
__ LoadFromOffset(
- R5, R2, kWordSize * SubtypeTestCache::kInstanceTypeArguments, kNoPP);
+ R5, R2, kWordSize * SubtypeTestCache::kInstanceTypeArguments);
__ CompareRegisters(R5, R4);
if (n == 2) {
__ b(&found, EQ);
} else {
__ b(&next_iteration, NE);
__ LoadFromOffset(R5, R2,
- kWordSize * SubtypeTestCache::kInstantiatorTypeArguments, kNoPP);
+ kWordSize * SubtypeTestCache::kInstantiatorTypeArguments);
__ CompareRegisters(R5, R1);
__ b(&found, EQ);
}
}
__ Bind(&next_iteration);
__ AddImmediate(
- R2, R2, kWordSize * SubtypeTestCache::kTestEntryLength, kNoPP);
+ R2, R2, kWordSize * SubtypeTestCache::kTestEntryLength);
__ b(&loop);
// Fall through to not found.
__ Bind(¬_found);
- __ LoadObject(R1, Object::null_object(), PP);
+ __ LoadObject(R1, Object::null_object());
__ ret();
__ Bind(&found);
- __ LoadFromOffset(R1, R2, kWordSize * SubtypeTestCache::kTestResult, kNoPP);
+ __ LoadFromOffset(R1, R2, kWordSize * SubtypeTestCache::kTestResult);
__ ret();
}
@@ -1994,10 +1961,10 @@
__ mov(THR, R5);
__ LoadIsolate(R5);
// Set the tag.
- __ LoadImmediate(R2, VMTag::kDartTagId, kNoPP);
- __ StoreToOffset(R2, R5, Isolate::vm_tag_offset(), kNoPP);
+ __ LoadImmediate(R2, VMTag::kDartTagId);
+ __ StoreToOffset(R2, R5, Isolate::vm_tag_offset());
// Clear top exit frame.
- __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset(), kNoPP);
+ __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
__ ret(); // Jump to the exception handler code.
}
@@ -2009,14 +1976,14 @@
__ EnterStubFrame();
__ Push(R4);
// Setup space on stack for the return value.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ Push(R6);
__ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1);
__ Pop(R0); // Discard argument.
__ Pop(R0); // Get Code object
__ Pop(R4); // Restore argument descriptor.
- __ LoadFieldFromOffset(R0, R0, Code::instructions_offset(), kNoPP);
- __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, PP);
+ __ LoadFieldFromOffset(R0, R0, Code::instructions_offset());
+ __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag);
__ LeaveStubFrame();
__ br(R0);
__ brk(0);
@@ -2035,11 +2002,9 @@
// Return Zero condition flag set if equal.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
- const Register left,
- const Register right,
- const Register unused1,
- const Register unused2) {
+static void GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ tsti(left, Immediate(kSmiTagMask));
@@ -2048,35 +2013,35 @@
__ b(&reference_compare, EQ);
// Value compare for two doubles.
- __ CompareClassId(left, kDoubleCid, kNoPP);
+ __ CompareClassId(left, kDoubleCid);
__ b(&check_mint, NE);
- __ CompareClassId(right, kDoubleCid, kNoPP);
+ __ CompareClassId(right, kDoubleCid);
__ b(&done, NE);
// Double values bitwise compare.
- __ LoadFieldFromOffset(left, left, Double::value_offset(), kNoPP);
- __ LoadFieldFromOffset(right, right, Double::value_offset(), kNoPP);
+ __ LoadFieldFromOffset(left, left, Double::value_offset());
+ __ LoadFieldFromOffset(right, right, Double::value_offset());
__ CompareRegisters(left, right);
__ b(&done);
__ Bind(&check_mint);
- __ CompareClassId(left, kMintCid, kNoPP);
+ __ CompareClassId(left, kMintCid);
__ b(&check_bigint, NE);
- __ CompareClassId(right, kMintCid, kNoPP);
+ __ CompareClassId(right, kMintCid);
__ b(&done, NE);
- __ LoadFieldFromOffset(left, left, Mint::value_offset(), kNoPP);
- __ LoadFieldFromOffset(right, right, Mint::value_offset(), kNoPP);
+ __ LoadFieldFromOffset(left, left, Mint::value_offset());
+ __ LoadFieldFromOffset(right, right, Mint::value_offset());
__ b(&done);
__ Bind(&check_bigint);
- __ CompareClassId(left, kBigintCid, kNoPP);
+ __ CompareClassId(left, kBigintCid);
__ b(&reference_compare, NE);
- __ CompareClassId(right, kBigintCid, kNoPP);
+ __ CompareClassId(right, kBigintCid);
__ b(&done, NE);
__ EnterStubFrame();
__ ReserveAlignedFrameSpace(2 * kWordSize);
- __ StoreToOffset(left, SP, 0 * kWordSize, kNoPP);
- __ StoreToOffset(right, SP, 1 * kWordSize, kNoPP);
+ __ StoreToOffset(left, SP, 0 * kWordSize);
+ __ StoreToOffset(right, SP, 1 * kWordSize);
__ CallRuntime(kBigintCompareRuntimeEntry, 2);
// Result in R0, 0 means equal.
__ LeaveStubFrame();
@@ -2100,17 +2065,16 @@
Label stepping, done_stepping;
if (FLAG_support_debugger) {
__ LoadIsolate(R1);
- __ LoadFromOffset(
- R1, R1, Isolate::single_step_offset(), kNoPP, kUnsignedByte);
- __ CompareImmediate(R1, 0, kNoPP);
+ __ LoadFromOffset(R1, R1, Isolate::single_step_offset(), kUnsignedByte);
+ __ CompareImmediate(R1, 0);
__ b(&stepping, NE);
__ Bind(&done_stepping);
}
const Register left = R1;
const Register right = R0;
- __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP);
- __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP);
+ __ LoadFromOffset(left, SP, 1 * kWordSize);
+ __ LoadFromOffset(right, SP, 0 * kWordSize);
GenerateIdenticalWithNumberCheckStub(assembler, left, right);
__ ret();
@@ -2131,12 +2095,11 @@
// Return Zero condition flag set if equal.
void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub(
Assembler* assembler) {
- const Register temp = R2;
const Register left = R1;
const Register right = R0;
- __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP);
- __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP);
- GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp);
+ __ LoadFromOffset(left, SP, 1 * kWordSize);
+ __ LoadFromOffset(right, SP, 0 * kWordSize);
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right);
__ ret();
}
@@ -2146,8 +2109,8 @@
ASSERT((cache != R0) && (cache != R2));
__ LoadTaggedClassIdMayBeSmi(R0, receiver);
// R0: class ID of the receiver (smi).
- __ LoadFieldFromOffset(R2, cache, MegamorphicCache::buckets_offset(), PP);
- __ LoadFieldFromOffset(R1, cache, MegamorphicCache::mask_offset(), PP);
+ __ LoadFieldFromOffset(R2, cache, MegamorphicCache::buckets_offset());
+ __ LoadFieldFromOffset(R1, cache, MegamorphicCache::mask_offset());
// R2: cache buckets array.
// R1: mask.
__ mov(R3, R0);
@@ -2162,7 +2125,7 @@
const intptr_t base = Array::data_offset();
// R3 is smi tagged, but table entries are 16 bytes, so LSL 3.
__ add(TMP, R2, Operand(R3, LSL, 3));
- __ LoadFieldFromOffset(R4, TMP, base, PP);
+ __ LoadFieldFromOffset(R4, TMP, base);
ASSERT(kIllegalCid == 0);
__ tst(R4, Operand(R4));
@@ -2176,11 +2139,11 @@
// illegal class id was found, the target is a cache miss handler that can
// be invoked as a normal Dart function.
__ add(TMP, R2, Operand(R3, LSL, 3));
- __ LoadFieldFromOffset(R0, TMP, base + kWordSize, PP);
- __ LoadFieldFromOffset(R1, R0, Function::instructions_offset(), PP);
+ __ LoadFieldFromOffset(R0, TMP, base + kWordSize);
+ __ LoadFieldFromOffset(R1, R0, Function::instructions_offset());
// TODO(srdjan): Evaluate performance impact of moving the instruction below
// to the call site, instead of having it here.
- __ AddImmediate(target, R1, Instructions::HeaderSize() - kHeapObjectTag, PP);
+ __ AddImmediate(target, R1, Instructions::HeaderSize() - kHeapObjectTag);
}
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index 94e40ab..142a824 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -45,9 +45,9 @@
const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
__ EnterDartFrame(0);
- __ PushObject(Object::null_object(), PP); // Push Null obj for return value.
- __ PushObject(smi1, PP); // Push argument 1 smi1.
- __ PushObject(smi2, PP); // Push argument 2 smi2.
+ __ PushObject(Object::null_object()); // Push Null obj for return value.
+ __ PushObject(smi1); // Push argument 1 smi1.
+ __ PushObject(smi2); // Push argument 2 smi2.
ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
__ CallRuntime(kTestSmiSubRuntimeEntry, argc); // Call SmiSub runtime func.
__ add(SP, SP, Operand(argc * kWordSize));
@@ -82,8 +82,8 @@
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
__ EnterDartFrame(0);
__ ReserveAlignedFrameSpace(0);
- __ LoadObject(R0, smi1, PP); // Set up argument 1 smi1.
- __ LoadObject(R1, smi2, PP); // Set up argument 2 smi2.
+ __ LoadObject(R0, smi1); // Set up argument 1 smi1.
+ __ LoadObject(R1, smi2); // Set up argument 2 smi2.
__ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2); // Call SmiAdd runtime func.
__ LeaveDartFrame();
__ ret(); // Return value is in R0.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 32505f3..3b21fb7 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -321,43 +321,16 @@
}
-// Called from array allocate instruction when the allocation stub has been
-// disabled.
-// EDX: length (preserved).
-// ECX: element type (preserved).
-void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ EnterStubFrame();
- __ pushl(EDX); // Preserve length.
- __ pushl(ECX); // Preserve element type.
- __ pushl(raw_null); // Setup space on stack for return value.
- __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
- __ popl(EAX); // Get Code object.
- __ popl(ECX); // Restore element type.
- __ popl(EDX); // Restore length.
- __ movl(EAX, FieldAddress(EAX, Code::instructions_offset()));
- __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
- __ LeaveFrame();
- __ jmp(EAX);
- __ int3();
-}
-
-
// Input parameters:
// EDX: smi-tagged argument count, may be zero.
// EBP[kParamEndSlotFromFp + 1]: last argument.
// Uses EAX, EBX, ECX, EDX, EDI.
static void PushArgumentsArray(Assembler* assembler) {
+ // Allocate array to store arguments of caller.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
- StubCode* stub_code = Isolate::Current()->stub_code();
-
- // Allocate array to store arguments of caller.
__ movl(ECX, raw_null); // Null element type for raw Array.
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ call(&array_label);
+ __ Call(*StubCode::AllocateArray_entry());
__ SmiUntag(EDX);
// EAX: newly allocated array.
// EDX: length of the array (was preserved by the stub).
@@ -582,23 +555,17 @@
// ECX : array element type (either NULL or an instantiated type).
// Uses EAX, EBX, ECX, EDI as temporary registers.
// The newly allocated object is returned in EAX.
-void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler,
- uword* entry_patch_offset, uword* patch_code_pc_offset) {
- *entry_patch_offset = assembler->CodeSize();
+void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
Label slow_case;
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
-
- Isolate* isolate = Isolate::Current();
- const Class& cls = Class::Handle(isolate->object_store()->array_class());
- ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
// Assert that length is a Smi.
__ testl(EDX, Immediate(kSmiTagMask));
- if (FLAG_use_slow_path || cls.trace_allocation()) {
+ if (FLAG_use_slow_path) {
__ jmp(&slow_case);
} else {
__ j(NOT_ZERO, &slow_case);
@@ -612,48 +579,53 @@
__ cmpl(EDX, max_len);
__ j(GREATER, &slow_case);
+ __ MaybeTraceAllocation(kArrayCid,
+ EAX,
+ &slow_case,
+ /* near_jump = */ false,
+ /* inline_isolate = */ false);
+
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
- __ leal(EDI, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi.
+ __ leal(EBX, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi.
ASSERT(kSmiTagShift == 1);
- __ andl(EDI, Immediate(-kObjectAlignment));
+ __ andl(EBX, Immediate(-kObjectAlignment));
// ECX: array element type.
// EDX: array length as Smi.
- // EDI: allocation size.
+ // EBX: allocation size.
- Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = Heap::SpaceForAllocation(cid);
- __ movl(EAX, Address::Absolute(heap->TopAddress(space)));
- __ movl(EBX, EAX);
-
- // EDI: allocation size.
- __ addl(EBX, EDI);
+ __ movl(EDI, Address(THR, Thread::heap_offset()));
+ __ movl(EAX, Address(EDI, Heap::TopOffset(space)));
+ __ addl(EBX, EAX);
__ j(CARRY, &slow_case);
// Check if the allocation fits into the remaining space.
// EAX: potential new object start.
// EBX: potential next object start.
- // EDI: allocation size.
+ // EDI: heap.
// ECX: array element type.
// EDX: array length as Smi).
- __ cmpl(EBX, Address::Absolute(heap->EndAddress(space)));
+ __ cmpl(EBX, Address(EDI, Heap::EndOffset(space)));
__ j(ABOVE_EQUAL, &slow_case);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ movl(Address::Absolute(heap->TopAddress(space)), EBX);
+ __ movl(Address(EDI, Heap::TopOffset(space)), EBX);
+ __ subl(EBX, EAX);
__ addl(EAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, EDI, kNoRegister, space);
+ __ UpdateAllocationStatsWithSize(cid, EBX, EDI, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// EAX: new object start as a tagged pointer.
- // EBX: new object end address.
- // EDI: allocation size.
+ // EBX: allocation size.
// ECX: array element type.
// EDX: array length as Smi.
{
Label size_tag_overflow, done;
+ __ movl(EDI, EBX);
__ cmpl(EDI, Immediate(RawObject::SizeTag::kMaxSizeTag));
__ j(ABOVE, &size_tag_overflow, Assembler::kNearJump);
__ shll(EDI, Immediate(RawObject::kSizeTagPos - kObjectAlignmentLog2));
@@ -668,7 +640,7 @@
__ movl(FieldAddress(EAX, Array::tags_offset()), EDI); // Tags.
}
// EAX: new object start as a tagged pointer.
- // EBX: new object end address.
+ // EBX: allocation size.
// ECX: array element type.
// EDX: Array length as Smi (preserved).
// Store the type argument field.
@@ -683,11 +655,12 @@
// Initialize all array elements to raw_null.
// EAX: new object start as a tagged pointer.
- // EBX: new object end address.
+ // EBX: allocation size.
// EDI: iterator which initially points to the start of the variable
// data area to be initialized.
// ECX: array element type.
// EDX: array length as Smi.
+ __ leal(EBX, FieldAddress(EAX, EBX, TIMES_1, 0));
__ leal(EDI, FieldAddress(EAX, sizeof(RawArray)));
Label done;
Label init_loop;
@@ -716,11 +689,6 @@
__ popl(EAX); // Pop return value from return slot.
__ LeaveFrame();
__ ret();
- // Emit function patching code. This will be swapped with the first 5 bytes
- // at entry point.
- *patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ jmp(&stub_code->FixAllocateArrayStubTargetLabel());
}
@@ -851,8 +819,7 @@
// EDX: number of context variables.
const intptr_t cid = kContextCid;
Heap::Space space = Heap::SpaceForAllocation(cid);
- __ LoadIsolate(ECX);
- __ movl(ECX, Address(ECX, Isolate::heap_offset()));
+ __ movl(ECX, Address(THR, Thread::heap_offset()));
__ movl(EAX, Address(ECX, Heap::TopOffset(space)));
__ addl(EBX, EAX);
// Check if the allocation fits into the remaining space.
@@ -877,9 +844,9 @@
// EBX: next object start.
// EDX: number of context variables.
__ movl(Address(ECX, Heap::TopOffset(space)), EBX);
- __ addl(EAX, Immediate(kHeapObjectTag));
// EBX: Size of allocation in bytes.
__ subl(EBX, EAX);
+ __ addl(EAX, Immediate(kHeapObjectTag));
// Generate isolate-independent code to allow sharing between isolates.
__ UpdateAllocationStatsWithSize(cid, EBX, EDI, space,
/* inline_isolate = */ false);
@@ -1066,21 +1033,23 @@
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
// EDX: instantiated type arguments (if is_cls_parameterized).
- Heap* heap = Isolate::Current()->heap();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
- __ movl(EAX, Address::Absolute(heap->TopAddress(space)));
+ __ movl(EDI, Address(THR, Thread::heap_offset()));
+ __ movl(EAX, Address(EDI, Heap::TopOffset(space)));
__ leal(EBX, Address(EAX, instance_size));
// Check if the allocation fits into the remaining space.
// EAX: potential new object start.
// EBX: potential next object start.
- __ cmpl(EBX, Address::Absolute(heap->EndAddress(space)));
+ // EDI: heap.
+ __ cmpl(EBX, Address(EDI, Heap::EndOffset(space)));
if (FLAG_use_slow_path) {
__ jmp(&slow_case);
} else {
__ j(ABOVE_EQUAL, &slow_case);
}
- __ movl(Address::Absolute(heap->TopAddress(space)), EBX);
- __ UpdateAllocationStats(cls.id(), ECX, space);
+ __ movl(Address(EDI, Heap::TopOffset(space)), EBX);
+ __ UpdateAllocationStats(cls.id(), ECX, space,
+ /* inline_isolate = */ false);
// EAX: new object start (untagged).
// EBX: next object start.
@@ -1164,8 +1133,7 @@
// Emit function patching code. This will be swapped with the first 5 bytes
// at entry point.
*patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ jmp(&stub_code->FixAllocationStubTargetLabel());
+ __ Jmp(*StubCode::FixAllocationStubTarget_entry());
}
@@ -1967,11 +1935,10 @@
// Return ZF set.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
- const Register left,
- const Register right,
- const Register temp,
- const Register unused) {
+static void GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ testl(left, Immediate(kSmiTagMask));
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index b605c5b..1f7e244 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -386,48 +386,16 @@
}
-// Called from array allocate instruction when the allocation stub has been
-// disabled.
-// A0: element type (preserved).
-// A1: length (preserved).
-void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) {
- __ Comment("FixAllocationStubTarget");
- __ EnterStubFrame();
- // Setup space on stack for return value.
- __ addiu(SP, SP, Immediate(-3 * kWordSize));
- __ sw(A0, Address(SP, 2 * kWordSize));
- __ sw(A1, Address(SP, 1 * kWordSize));
- __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
- __ sw(TMP, Address(SP, 0 * kWordSize));
- __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
- // Get Code object result.
- __ lw(T0, Address(SP, 0 * kWordSize));
- __ lw(A1, Address(SP, 1 * kWordSize));
- __ lw(A0, Address(SP, 2 * kWordSize));
- __ addiu(SP, SP, Immediate(3 * kWordSize));
-
- // Jump to the dart function.
- __ lw(T0, FieldAddress(T0, Code::instructions_offset()));
- __ AddImmediate(T0, T0, Instructions::HeaderSize() - kHeapObjectTag);
-
- // Remove the stub frame.
- __ LeaveStubFrameAndReturn(T0);
-}
-
-
// Input parameters:
// A1: Smi-tagged argument count, may be zero.
// FP[kParamEndSlotFromFp + 1]: Last argument.
static void PushArgumentsArray(Assembler* assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
__ Comment("PushArgumentsArray");
// Allocate array to store arguments of caller.
__ LoadImmediate(A0, reinterpret_cast<intptr_t>(Object::null()));
// A0: Null element type for raw Array.
// A1: Smi-tagged argument count, may be zero.
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ BranchLink(&array_label);
+ __ BranchLink(*StubCode::AllocateArray_entry());
__ Comment("PushArgumentsArray return");
// V0: newly allocated array.
// A1: Smi-tagged argument count, may be zero (was preserved by the stub).
@@ -688,15 +656,9 @@
// A0: array element type (either NULL or an instantiated type).
// NOTE: A1 cannot be clobbered here as the caller relies on it being saved.
// The newly allocated object is returned in V0.
-void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler,
- uword* entry_patch_offset, uword* patch_code_pc_offset) {
+void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
__ Comment("AllocateArrayStub");
- *entry_patch_offset = assembler->CodeSize();
Label slow_case;
- Isolate* isolate = Isolate::Current();
- const Class& cls = Class::Handle(isolate->object_store()->array_class());
- ASSERT(!cls.IsNull());
-
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
@@ -704,7 +666,7 @@
// Check that length is a positive Smi.
__ andi(CMPRES1, T3, Immediate(kSmiTagMask));
- if (FLAG_use_slow_path || cls.trace_allocation()) {
+ if (FLAG_use_slow_path) {
__ b(&slow_case);
} else {
__ bne(CMPRES1, ZR, &slow_case);
@@ -716,6 +678,10 @@
reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements));
__ BranchUnsignedGreater(T3, Immediate(max_len), &slow_case);
+ const intptr_t cid = kArrayCid;
+ __ MaybeTraceAllocation(kArrayCid, T4, &slow_case,
+ /* inline_isolate = */ false);
+
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ LoadImmediate(T2, fixed_size);
__ sll(T3, T3, 1); // T3 is a Smi.
@@ -726,11 +692,11 @@
// T2: Allocation size.
- Heap* heap = isolate->heap();
- const intptr_t cid = kArrayCid;
Heap::Space space = Heap::SpaceForAllocation(cid);
- __ LoadImmediate(T3, heap->TopAddress(space));
- __ lw(T0, Address(T3, 0)); // Potential new object start.
+ __ LoadIsolate(T3);
+ __ lw(T3, Address(T3, Isolate::heap_offset()));
+ // Potential new object start.
+ __ lw(T0, Address(T3, Heap::TopOffset(space)));
__ addu(T1, T0, T2); // Potential next object start.
__ BranchUnsignedLess(T1, T0, &slow_case); // Branch on unsigned overflow.
@@ -739,15 +705,17 @@
// T0: potential new object start.
// T1: potential next object start.
// T2: allocation size.
- __ LoadImmediate(T4, heap->EndAddress(space));
- __ lw(T4, Address(T4, 0));
+ // T3: heap.
+ __ lw(T4, Address(T3, Heap::EndOffset(space)));
__ BranchUnsignedGreaterEqual(T1, T4, &slow_case);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ sw(T1, Address(T3, 0));
+ // T3: heap.
+ __ sw(T1, Address(T3, Heap::TopOffset(space)));
__ addiu(T0, T0, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, T2, T4, space);
+ __ UpdateAllocationStatsWithSize(cid, T2, T4, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// T0: new object start as a tagged pointer.
@@ -827,9 +795,6 @@
__ addiu(SP, SP, Immediate(3 * kWordSize));
__ LeaveStubFrameAndReturn();
- *patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->FixAllocateArrayStubTargetLabel());
}
@@ -1192,17 +1157,16 @@
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
// T1: instantiated type arguments (if is_cls_parameterized).
- Heap* heap = Isolate::Current()->heap();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
- __ LoadImmediate(T5, heap->TopAddress(space));
- __ lw(T2, Address(T5));
+ __ lw(T5, Address(THR, Thread::heap_offset()));
+ __ lw(T2, Address(T5, Heap::TopOffset(space)));
__ LoadImmediate(T4, instance_size);
__ addu(T3, T2, T4);
// Check if the allocation fits into the remaining space.
// T2: potential new object start.
// T3: potential next object start.
- __ LoadImmediate(TMP, heap->EndAddress(space));
- __ lw(CMPRES1, Address(TMP));
+ // T5: heap.
+ __ lw(CMPRES1, Address(T5, Heap::EndOffset(space)));
if (FLAG_use_slow_path) {
__ b(&slow_case);
} else {
@@ -1210,8 +1174,8 @@
}
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ sw(T3, Address(T5));
- __ UpdateAllocationStats(cls.id(), T5, space);
+ __ sw(T3, Address(T5, Heap::TopOffset(space)));
+ __ UpdateAllocationStats(cls.id(), T5, space, /* inline_isolate = */ false);
// T2: new object start.
// T3: next object start.
@@ -1295,8 +1259,7 @@
// Restore the frame pointer and return.
__ LeaveStubFrameAndReturn(RA);
*patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ BranchPatchable(&stub_code->FixAllocationStubTargetLabel());
+ __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry());
}
@@ -2138,11 +2101,11 @@
// Returns: CMPRES1 is zero if equal, non-zero otherwise.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
- const Register left,
- const Register right,
- const Register temp1,
- const Register temp2) {
+static void GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp1,
+ const Register temp2) {
__ Comment("IdenticalWithNumberCheckStub");
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index eaf3e41..cdbcabb 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -276,7 +276,7 @@
__ EnterStubFrame();
__ pushq(R10); // Preserve arguments descriptor array.
// Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
__ popq(RAX); // Get Code object result.
__ popq(R10); // Restore arguments descriptor array.
@@ -296,7 +296,7 @@
__ EnterStubFrame();
__ pushq(R10); // Preserve arguments descriptor array.
// Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ CallRuntime(kFixCallersTargetRuntimeEntry, 0);
__ popq(RAX); // Get Code object.
__ popq(R10); // Restore arguments descriptor array.
@@ -313,7 +313,7 @@
void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) {
__ EnterStubFrame();
// Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
__ popq(RAX); // Get Code object.
__ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
@@ -324,40 +324,14 @@
}
-// Called from array allocate instruction when the allocation stub has been
-// disabled.
-// R10: length (preserved).
-// RBX: element type (preserved).
-void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) {
- __ EnterStubFrame();
- __ pushq(R10); // Preserve length.
- __ pushq(RBX); // Preserve element type.
- // Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
- __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
- __ popq(RAX); // Get Code object.
- __ popq(RBX); // Restore element type.
- __ popq(R10); // Restore length.
- __ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
- __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
- __ LeaveStubFrame();
- __ jmp(RAX);
- __ int3();
-}
-
-
// Input parameters:
// R10: smi-tagged argument count, may be zero.
// RBP[kParamEndSlotFromFp + 1]: last argument.
static void PushArgumentsArray(Assembler* assembler) {
- StubCode* stub_code = Isolate::Current()->stub_code();
-
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
// Allocate array to store arguments of caller.
__ movq(RBX, R12); // Null element type for raw Array.
- const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
- const ExternalLabel array_label(array_stub.EntryPoint());
- __ call(&array_label);
+ __ Call(*StubCode::AllocateArray_entry());
__ SmiUntag(R10);
// RAX: newly allocated array.
// R10: length of the array (was preserved by the stub).
@@ -572,7 +546,7 @@
__ pushq(R10);
// Space for the result of the runtime call.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ pushq(RAX); // Receiver.
__ pushq(RBX); // IC data.
__ pushq(R10); // Arguments descriptor.
@@ -604,23 +578,15 @@
// RBX : array element type (either NULL or an instantiated type).
// NOTE: R10 cannot be clobbered here as the caller relies on it being saved.
// The newly allocated object is returned in RAX.
-void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler,
- uword* entry_patch_offset, uword* patch_code_pc_offset) {
- // Must load pool pointer before being able to patch.
- Register new_pp = R13;
- __ LoadPoolPointer(new_pp);
- *entry_patch_offset = assembler->CodeSize();
+void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
Label slow_case;
- Isolate* isolate = Isolate::Current();
- const Class& cls = Class::Handle(isolate->object_store()->array_class());
- ASSERT(!cls.IsNull());
// Compute the size to be allocated, it is based on the array length
// and is computed as:
// RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
__ movq(RDI, R10); // Array Length.
// Check that length is a positive Smi.
__ testq(RDI, Immediate(kSmiTagMask));
- if (FLAG_use_slow_path || cls.trace_allocation()) {
+ if (FLAG_use_slow_path) {
__ jmp(&slow_case);
} else {
__ j(NOT_ZERO, &slow_case);
@@ -632,16 +598,22 @@
Immediate(reinterpret_cast<int64_t>(Smi::New(Array::kMaxElements)));
__ cmpq(RDI, max_len);
__ j(GREATER, &slow_case);
+
+ // Check for allocation tracing.
+ __ MaybeTraceAllocation(kArrayCid,
+ &slow_case,
+ /* near_jump = */ false,
+ /* inline_isolate = */ false);
+
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ leaq(RDI, Address(RDI, TIMES_4, fixed_size)); // RDI is a Smi.
ASSERT(kSmiTagShift == 1);
__ andq(RDI, Immediate(-kObjectAlignment));
- Heap* heap = isolate->heap();
const intptr_t cid = kArrayCid;
Heap::Space space = Heap::SpaceForAllocation(cid);
- __ movq(RAX, Immediate(heap->TopAddress(space)));
- __ movq(RAX, Address(RAX, 0));
+ __ movq(R13, Address(THR, Thread::heap_offset()));
+ __ movq(RAX, Address(R13, Heap::TopOffset(space)));
// RDI: allocation size.
__ movq(RCX, RAX);
@@ -652,16 +624,16 @@
// RAX: potential new object start.
// RCX: potential next object start.
// RDI: allocation size.
- __ movq(R13, Immediate(heap->EndAddress(space)));
- __ cmpq(RCX, Address(R13, 0));
+ // R13: heap.
+ __ cmpq(RCX, Address(R13, Heap::EndOffset(space)));
__ j(ABOVE_EQUAL, &slow_case);
// Successfully allocated the object(s), now update top to point to
// next object start and initialize the object.
- __ movq(R13, Immediate(heap->TopAddress(space)));
- __ movq(Address(R13, 0), RCX);
+ __ movq(Address(R13, Heap::TopOffset(space)), RCX);
__ addq(RAX, Immediate(kHeapObjectTag));
- __ UpdateAllocationStatsWithSize(cid, RDI, space);
+ __ UpdateAllocationStatsWithSize(cid, RDI, space,
+ /* inline_isolate = */ false);
// Initialize the tags.
// RAX: new object start as a tagged pointer.
// RDI: allocation size.
@@ -697,7 +669,7 @@
// RCX: new object end address.
// RDI: iterator which initially points to the start of the variable
// data area to be initialized.
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
__ leaq(RDI, FieldAddress(RAX, sizeof(RawArray)));
Label done;
Label init_loop;
@@ -723,7 +695,7 @@
// calling into the runtime.
__ EnterStubFrame();
// Setup space on stack for return value.
- __ PushObject(Object::null_object(), PP);
+ __ PushObject(Object::null_object());
__ pushq(R10); // Array length as Smi.
__ pushq(RBX); // Element type.
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
@@ -732,9 +704,6 @@
__ popq(RAX); // Pop return value from return slot.
__ LeaveStubFrame();
__ ret();
- *patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ JmpPatchable(&stub_code->FixAllocateArrayStubTargetLabel(), new_pp);
}
@@ -770,7 +739,7 @@
// We now load the pool pointer(PP) as we are about to invoke dart code and we
// could potentially invoke some intrinsic functions which need the PP to be
// set up.
- __ LoadPoolPointer(PP);
+ __ LoadPoolPointer();
// If any additional (or fewer) values are pushed, the offsets in
// kExitLinkSlotFromEntryFp will need to be changed.
@@ -864,6 +833,7 @@
// Restore C++ ABI callee-saved registers.
__ PopRegisters(CallingConventions::kCalleeSaveCpuRegisters,
CallingConventions::kCalleeSaveXmmRegisters);
+ __ set_constant_pool_allowed(false);
// Restore the frame pointer.
__ LeaveFrame();
@@ -878,7 +848,7 @@
// Output:
// RAX: new allocated RawContext object.
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
if (FLAG_inline_alloc) {
Label slow_case;
// First compute the rounded instance size.
@@ -891,8 +861,7 @@
// R10: number of context variables.
const intptr_t cid = kContextCid;
Heap::Space space = Heap::SpaceForAllocation(cid);
- __ LoadIsolate(RCX);
- __ movq(RCX, Address(RCX, Isolate::heap_offset()));
+ __ movq(RCX, Address(THR, Thread::heap_offset()));
__ movq(RAX, Address(RCX, Heap::TopOffset(space)));
__ addq(R13, RAX);
// Check if the allocation fits into the remaining space.
@@ -914,9 +883,9 @@
// R10: number of context variables.
// RCX: heap.
__ movq(Address(RCX, Heap::TopOffset(space)), R13);
- __ addq(RAX, Immediate(kHeapObjectTag));
// R13: Size of allocation in bytes.
__ subq(R13, RAX);
+ __ addq(RAX, Immediate(kHeapObjectTag));
// Generate isolate-independent code to allow sharing between isolates.
__ UpdateAllocationStatsWithSize(cid, R13, space,
/* inline_isolate */ false);
@@ -1091,7 +1060,7 @@
const int kInlineInstanceSize = 12; // In words.
const intptr_t instance_size = cls.instance_size();
ASSERT(instance_size > 0);
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
if (is_cls_parameterized) {
__ movq(RDX, Address(RSP, kObjectTypeArgumentsOffset));
// RDX: instantiated type arguments.
@@ -1102,24 +1071,22 @@
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
// RDX: instantiated type arguments (if is_cls_parameterized).
- Heap* heap = Isolate::Current()->heap();
Heap::Space space = Heap::SpaceForAllocation(cls.id());
- __ movq(RCX, Immediate(heap->TopAddress(space)));
- __ movq(RAX, Address(RCX, 0));
+ __ movq(RCX, Address(THR, Thread::heap_offset()));
+ __ movq(RAX, Address(RCX, Heap::TopOffset(space)));
__ leaq(RBX, Address(RAX, instance_size));
// Check if the allocation fits into the remaining space.
// RAX: potential new object start.
// RBX: potential next object start.
- // RCX: heap top address.
- __ movq(R13, Immediate(heap->EndAddress(space)));
- __ cmpq(RBX, Address(R13, 0));
+ // RCX: heap.
+ __ cmpq(RBX, Address(RCX, Heap::EndOffset(space)));
if (FLAG_use_slow_path) {
__ jmp(&slow_case);
} else {
__ j(ABOVE_EQUAL, &slow_case);
}
- __ movq(Address(RCX, 0), RBX);
- __ UpdateAllocationStats(cls.id(), space);
+ __ movq(Address(RCX, Heap::TopOffset(space)), RBX);
+ __ UpdateAllocationStats(cls.id(), space, /* inline_isolate = */ false);
// RAX: new object start (untagged).
// RBX: next object start.
@@ -1187,7 +1154,7 @@
// Create a stub frame.
__ EnterStubFrame(); // Uses PP to access class object.
__ pushq(R12); // Setup space on stack for return value.
- __ PushObject(cls, PP); // Push class of object to be allocated.
+ __ PushObject(cls); // Push class of object to be allocated.
if (is_cls_parameterized) {
__ pushq(RDX); // Push type arguments of object to be allocated.
} else {
@@ -1202,8 +1169,7 @@
__ LeaveStubFrame();
__ ret();
*patch_code_pc_offset = assembler->CodeSize();
- StubCode* stub_code = Isolate::Current()->stub_code();
- __ JmpPatchable(&stub_code->FixAllocationStubTargetLabel(), new_pp);
+ __ JmpPatchable(*StubCode::FixAllocationStubTarget_entry(), new_pp);
}
@@ -1221,7 +1187,7 @@
__ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
__ movq(RAX, Address(RBP, R13, TIMES_4, kParamEndSlotFromFp * kWordSize));
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
__ pushq(R12); // Setup space on stack for result from noSuchMethod.
__ pushq(RAX); // Receiver.
__ pushq(R10); // Arguments descriptor array.
@@ -1308,10 +1274,10 @@
Label done, is_true;
__ cmpq(RAX, RCX);
__ j(EQUAL, &is_true, Assembler::kNearJump);
- __ LoadObject(RAX, Bool::False(), PP);
+ __ LoadObject(RAX, Bool::False());
__ jmp(&done, Assembler::kNearJump);
__ Bind(&is_true);
- __ LoadObject(RAX, Bool::True(), PP);
+ __ LoadObject(RAX, Bool::True());
__ Bind(&done);
break;
}
@@ -1479,7 +1445,7 @@
__ j(NOT_EQUAL, &loop, Assembler::kNearJump);
__ Comment("IC miss");
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
// Compute address of arguments (first read number of arguments from
// arguments descriptor array and then compute address on the stack).
__ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
@@ -1797,7 +1763,7 @@
__ pushq(RBX);
// Room for result. Debugger stub returns address of the
// unpatched runtime stub.
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
__ pushq(R12); // Room for result.
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
__ popq(RAX); // Address of original.
@@ -1812,7 +1778,7 @@
__ EnterStubFrame();
// Room for result. Debugger stub returns address of the
// unpatched runtime stub.
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
__ pushq(R12); // Room for result.
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
__ popq(RAX); // Address of original.
@@ -1852,9 +1818,9 @@
const intptr_t kInstanceOffsetInBytes = 2 * kWordSize;
const intptr_t kCacheOffsetInBytes = 3 * kWordSize;
__ movq(RAX, Address(RSP, kInstanceOffsetInBytes));
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
if (n > 1) {
- __ LoadClass(R10, RAX, kNoRegister);
+ __ LoadClass(R10, RAX);
// Compute instance type arguments into R13.
Label has_no_type_arguments;
__ movq(R13, R12);
@@ -2003,7 +1969,7 @@
// R10: argument descriptor (preserved).
void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
__ EnterStubFrame();
- __ LoadObject(R12, Object::null_object(), PP);
+ __ LoadObject(R12, Object::null_object());
__ pushq(R10);
__ pushq(R12); // Setup space on stack for return value.
__ pushq(RDI);
@@ -2031,11 +1997,9 @@
// Return ZF set.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
- const Register left,
- const Register right,
- const Register unused1,
- const Register unused2) {
+static void GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ testq(left, Immediate(kSmiTagMask));
@@ -2151,7 +2115,7 @@
__ jmp(&loop);
__ Bind(&update);
- __ AddImmediate(RCX, Immediate(Smi::RawValue(1)), PP);
+ __ AddImmediate(RCX, Immediate(Smi::RawValue(1)));
__ Bind(&loop);
__ andq(RCX, RBX);
const intptr_t base = Array::data_offset();
@@ -2174,7 +2138,7 @@
// TODO(srdjan): Evaluate performance impact of moving the instruction below
// to the call site, instead of having it here.
__ AddImmediate(
- target, Immediate(Instructions::HeaderSize() - kHeapObjectTag), PP);
+ target, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
}
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index c91ae77..4f67eed 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -45,12 +45,12 @@
const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
__ EnterStubFrame();
- __ PushObject(Object::null_object(), PP); // Push Null obj for return value.
- __ PushObject(smi1, PP); // Push argument 1 smi1.
- __ PushObject(smi2, PP); // Push argument 2 smi2.
+ __ PushObject(Object::null_object()); // Push Null obj for return value.
+ __ PushObject(smi1); // Push argument 1 smi1.
+ __ PushObject(smi2); // Push argument 2 smi2.
ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
__ CallRuntime(kTestSmiSubRuntimeEntry, argc); // Call SmiSub runtime func.
- __ AddImmediate(RSP, Immediate(argc * kWordSize), PP);
+ __ AddImmediate(RSP, Immediate(argc * kWordSize));
__ popq(RAX); // Pop return value from return slot.
__ LeaveStubFrame();
__ ret();
@@ -82,8 +82,8 @@
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
__ enter(Immediate(0));
__ ReserveAlignedFrameSpace(0);
- __ LoadObject(CallingConventions::kArg1Reg, smi1, PP);
- __ LoadObject(CallingConventions::kArg2Reg, smi2, PP);
+ __ LoadObject(CallingConventions::kArg1Reg, smi1);
+ __ LoadObject(CallingConventions::kArg2Reg, smi2);
__ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2); // Call SmiAdd runtime func.
__ leave();
__ ret(); // Return value is in RAX.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index ee8a711..2cdaf9e 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -389,6 +389,7 @@
V(last, "last") \
V(removeLast, "removeLast") \
V(add, "add") \
+ V(ConstructorClosurePrefix, "new#") \
// Contains a list of frequently used strings in a canonicalized form. This
@@ -503,6 +504,9 @@
static const String& At() {
return *(symbol_handles_[kNullCharId + '@']);
}
+ static const String& HashMark() {
+ return *(symbol_handles_[kNullCharId + '#']);
+ }
static const String& Semicolon() {
return *(symbol_handles_[kNullCharId + ';']);
}
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index 50e5e23..ffd224f 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -81,11 +81,13 @@
};
-VMTagScope::VMTagScope(Isolate* base_isolate, uword tag)
+VMTagScope::VMTagScope(Isolate* base_isolate, uword tag, bool conditional_set)
: StackResource(base_isolate) {
ASSERT(isolate() != NULL);
previous_tag_ = isolate()->vm_tag();
- isolate()->set_vm_tag(tag);
+ if (conditional_set) {
+ isolate()->set_vm_tag(tag);
+ }
}
diff --git a/runtime/vm/tags.h b/runtime/vm/tags.h
index e0077cb..6b16be3 100644
--- a/runtime/vm/tags.h
+++ b/runtime/vm/tags.h
@@ -22,6 +22,9 @@
V(CompileClass) \
V(CompileTopLevel) \
V(CompileScanner) \
+ V(CompileParseFunction) \
+ V(CompileParseRegExp) \
+ V(CompileFlowGraphBuilder) \
V(Dart) \
V(GCNewSpace) \
V(GCOldSpace) \
@@ -40,6 +43,13 @@
kNumVMTags,
kRootTagId, // Special tag used as root of all profiles.
kTruncatedTagId, // Special tag used to indicate a truncated call stack.
+ // ProfileInfo tags.
+ kNoneCodeTagId,
+ kOptimizedCodeTagId,
+ kUnoptimizedCodeTagId,
+ kNativeCodeTagId,
+ kInlineStartCodeTagId,
+ kInlineEndCodeTagId,
kLastTagId,
};
@@ -65,7 +75,7 @@
class VMTagScope : StackResource {
public:
- VMTagScope(Isolate* isolate, uword tag);
+ VMTagScope(Isolate* isolate, uword tag, bool conditional_set = true);
~VMTagScope();
private:
uword previous_tag_;
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index bbdd1b4..aa4f67e 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -123,9 +123,9 @@
Thread* thread = Thread::Current();
ASSERT(thread != NULL);
ASSERT(thread->isolate() == NULL);
- ASSERT(isolate->mutator_thread() == NULL);
+ ASSERT(!isolate->HasMutatorThread());
thread->isolate_ = isolate;
- isolate->set_mutator_thread(thread);
+ isolate->MakeCurrentThreadMutator(thread);
// TODO(koda): Migrate thread_state_ and profile_data_ to Thread, to allow
// helper threads concurrent with mutator.
ASSERT(isolate->thread_state() == NULL);
@@ -140,6 +140,8 @@
isolate->set_vm_tag(VMTag::kVMTagId);
ASSERT(thread->store_buffer_block_ == NULL);
thread->store_buffer_block_ = isolate->store_buffer()->PopBlock();
+ ASSERT(isolate->heap() != NULL);
+ thread->heap_ = isolate->heap();
thread->Schedule(isolate);
}
@@ -160,9 +162,10 @@
}
isolate->set_thread_state(NULL);
Profiler::EndExecution(isolate);
- isolate->set_mutator_thread(NULL);
+ isolate->ClearMutatorThread();
thread->isolate_ = NULL;
ASSERT(Isolate::Current() == NULL);
+ thread->heap_ = NULL;
}
@@ -171,9 +174,11 @@
ASSERT(thread != NULL);
ASSERT(thread->isolate() == NULL);
thread->isolate_ = isolate;
+ ASSERT(isolate->heap() != NULL);
+ thread->heap_ = isolate->heap();
// Do not update isolate->mutator_thread, but perform sanity check:
// this thread should not be both the main mutator and helper.
- ASSERT(isolate->mutator_thread() != thread);
+ ASSERT(!isolate->MutatorThreadIsCurrentThread());
thread->Schedule(isolate);
}
@@ -187,7 +192,8 @@
ASSERT(isolate != NULL);
thread->Unschedule();
thread->isolate_ = NULL;
- ASSERT(isolate->mutator_thread() != thread);
+ thread->heap_ = NULL;
+ ASSERT(!isolate->MutatorThreadIsCurrentThread());
}
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 98cd55d..2b2d343 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -13,6 +13,7 @@
class CHA;
class HandleScope;
+class Heap;
class Isolate;
class Object;
class RawBool;
@@ -20,6 +21,7 @@
class StackResource;
class Zone;
+
// List of VM-global objects/addresses cached in each Thread object.
#define CACHED_VM_OBJECTS_LIST(V) \
V(RawObject*, object_null_, Object::null(), NULL) \
@@ -28,7 +30,7 @@
#define CACHED_ADDRESSES_LIST(V) \
V(uword, update_store_buffer_entry_point_, \
- StubCode::UpdateStoreBufferEntryPoint(), 0)
+ StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0)
#define CACHED_CONSTANTS_LIST(V) \
CACHED_VM_OBJECTS_LIST(V) \
@@ -117,6 +119,10 @@
return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_resource);
}
+ static intptr_t heap_offset() {
+ return OFFSET_OF(Thread, heap_);
+ }
+
int32_t no_handle_scope_depth() const {
#if defined(DEBUG)
return state_.no_handle_scope_depth;
@@ -153,6 +159,28 @@
#endif
}
+ int32_t no_safepoint_scope_depth() const {
+#if defined(DEBUG)
+ return state_.no_safepoint_scope_depth;
+#else
+ return 0;
+#endif
+ }
+
+ void IncrementNoSafepointScopeDepth() {
+#if defined(DEBUG)
+ ASSERT(state_.no_safepoint_scope_depth < INT_MAX);
+ state_.no_safepoint_scope_depth += 1;
+#endif
+ }
+
+ void DecrementNoSafepointScopeDepth() {
+#if defined(DEBUG)
+ ASSERT(state_.no_safepoint_scope_depth > 0);
+ state_.no_safepoint_scope_depth -= 1;
+#endif
+ }
+
// Collection of isolate-specific state of a thread that is saved/restored
// on isolate exit/re-entry.
struct State {
@@ -162,6 +190,7 @@
#if defined(DEBUG)
HandleScope* top_handle_scope;
intptr_t no_handle_scope_depth;
+ int32_t no_safepoint_scope_depth;
#endif
};
@@ -179,6 +208,7 @@
static ThreadLocalKey thread_key_;
Isolate* isolate_;
+ Heap* heap_;
State state_;
StoreBufferBlock* store_buffer_block_;
#define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value) \
@@ -207,6 +237,7 @@
void Schedule(Isolate* isolate);
void Unschedule();
+ friend class ApiZone;
friend class Isolate;
friend class StackZone;
DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
new file mode 100644
index 0000000..8ade009
--- /dev/null
+++ b/runtime/vm/thread_registry.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/thread_registry.h"
+
+#include "vm/isolate.h"
+#include "vm/lockers.h"
+
+namespace dart {
+
+void ThreadRegistry::SafepointThreads() {
+ MonitorLocker ml(monitor_);
+ // First wait for any older rounds that are still in progress.
+ while (in_rendezvous_) {
+ // Assert we are not the organizer trying to nest calls to SafepointThreads.
+ ASSERT(remaining_ > 0);
+ CheckSafepointLocked();
+ }
+ // Start a new round.
+ in_rendezvous_ = true;
+ ++round_; // Overflows after 240+ years @ 10^9 safepoints per second.
+ remaining_ = CountScheduledLocked();
+ Isolate* isolate = Isolate::Current();
+ // We only expect this method to be called from within the isolate itself.
+ ASSERT(isolate->thread_registry() == this);
+ // TODO(koda): Rename Thread::PrepareForGC and call it here?
+ --remaining_; // Exclude this thread from the count.
+ // Ensure the main mutator will reach a safepoint (could be running Dart).
+ if (!isolate->MutatorThreadIsCurrentThread()) {
+ isolate->ScheduleInterrupts(Isolate::kVMInterrupt);
+ }
+ while (remaining_ > 0) {
+ ml.Wait(Monitor::kNoTimeout);
+ }
+}
+
+
+void ThreadRegistry::ResumeAllThreads() {
+ MonitorLocker ml(monitor_);
+ ASSERT(in_rendezvous_);
+ in_rendezvous_ = false;
+ ml.NotifyAll();
+}
+
+
+void ThreadRegistry::CheckSafepointLocked() {
+ int64_t last_round = -1;
+ while (in_rendezvous_) {
+ ASSERT(round_ >= last_round);
+ if (round_ != last_round) {
+ ASSERT((last_round == -1) || (round_ == (last_round + 1)));
+ last_round = round_;
+ // Participate in this round.
+ // TODO(koda): Rename Thread::PrepareForGC and call it here?
+ if (--remaining_ == 0) {
+ // Ensure the organizing thread is notified.
+ // TODO(koda): Use separate condition variables and plain 'Notify'.
+ monitor_->NotifyAll();
+ }
+ }
+ monitor_->Wait(Monitor::kNoTimeout);
+ // Note: Here, round_ is needed to detect and distinguish two cases:
+ // a) The old rendezvous is still in progress, so just keep waiting, or
+ // b) after ResumeAllThreads, another call to SafepointThreads was
+ // made before this thread got a chance to reaquire monitor_, thus this
+ // thread should (again) decrease remaining_ to indicate cooperation in
+ // this new round.
+ }
+}
+
+
+intptr_t ThreadRegistry::CountScheduledLocked() {
+ intptr_t count = 0;
+ for (int i = 0; i < entries_.length(); ++i) {
+ const Entry& entry = entries_[i];
+ if (entry.scheduled) {
+ ++count;
+ }
+ }
+ return count;
+}
+
+} // namespace dart
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index af16026..f8f324d 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -16,10 +16,41 @@
// Unordered collection of threads relating to a particular isolate.
class ThreadRegistry {
public:
- ThreadRegistry() : mutex_(new Mutex()), entries_() {}
+ ThreadRegistry()
+ : monitor_(new Monitor()),
+ entries_(),
+ in_rendezvous_(false),
+ remaining_(0),
+ round_(0) {}
+
+ // Bring all threads in this isolate to a safepoint. The caller is
+ // expected to be implicitly at a safepoint. The threads will wait
+ // until ResumeAllThreads is called. First participates in any
+ // already pending rendezvous requested by another thread. Any
+ // thread that tries to enter this isolate during rendezvous will
+ // wait in RestoreStateTo. Nesting is not supported: the caller must
+ // call ResumeAllThreads before making further calls to
+ // SafepointThreads.
+ void SafepointThreads();
+
+ // Unblocks all threads participating in the rendezvous that was organized
+ // by a prior call to SafepointThreads.
+ // TODO(koda): Consider adding a scope helper to avoid omitting this call.
+ void ResumeAllThreads();
+
+ // Indicate that the current thread is at a safepoint, and offer to wait for
+ // any pending rendezvous request (if none, returns immediately).
+ void CheckSafepoint() {
+ MonitorLocker ml(monitor_);
+ CheckSafepointLocked();
+ }
bool RestoreStateTo(Thread* thread, Thread::State* state) {
- MutexLocker ml(mutex_);
+ MonitorLocker ml(monitor_);
+ // Wait for any rendezvous in progress.
+ while (in_rendezvous_) {
+ ml.Wait(Monitor::kNoTimeout);
+ }
Entry* entry = FindEntry(thread);
if (entry != NULL) {
Thread::State st = entry->state;
@@ -50,21 +81,28 @@
}
void SaveStateFrom(Thread* thread, const Thread::State& state) {
- MutexLocker ml(mutex_);
+ MonitorLocker ml(monitor_);
Entry* entry = FindEntry(thread);
ASSERT(entry != NULL);
ASSERT(entry->scheduled);
entry->scheduled = false;
entry->state = state;
+ if (in_rendezvous_) {
+ // Don't wait for this thread.
+ ASSERT(remaining_ > 0);
+ if (--remaining_ == 0) {
+ ml.NotifyAll();
+ }
+ }
}
bool Contains(Thread* thread) {
- MutexLocker ml(mutex_);
+ MonitorLocker ml(monitor_);
return (FindEntry(thread) != NULL);
}
void CheckNotScheduled(Isolate* isolate) {
- MutexLocker ml(mutex_);
+ MonitorLocker ml(monitor_);
for (int i = 0; i < entries_.length(); ++i) {
const Entry& entry = entries_[i];
if (entry.scheduled) {
@@ -77,7 +115,7 @@
}
void VisitObjectPointers(ObjectPointerVisitor* visitor) {
- MutexLocker ml(mutex_);
+ MonitorLocker ml(monitor_);
for (int i = 0; i < entries_.length(); ++i) {
const Entry& entry = entries_[i];
Zone* zone = entry.scheduled ? entry.thread->zone() : entry.state.zone;
@@ -96,8 +134,8 @@
// Returns Entry corresponding to thread in registry or NULL.
// Note: Lock should be taken before this function is called.
+ // TODO(koda): Add method Monitor::IsOwnedByCurrentThread.
Entry* FindEntry(Thread* thread) {
- DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
for (int i = 0; i < entries_.length(); ++i) {
if (entries_[i].thread == thread) {
return &entries_[i];
@@ -106,9 +144,21 @@
return NULL;
}
- Mutex* mutex_;
+ // Note: Lock should be taken before this function is called.
+ void CheckSafepointLocked();
+
+ // Returns the number threads that are scheduled on this isolate.
+ // Note: Lock should be taken before this function is called.
+ intptr_t CountScheduledLocked();
+
+ Monitor* monitor_; // All access is synchronized through this monitor.
MallocGrowableArray<Entry> entries_;
+ // Safepoint rendezvous state.
+ bool in_rendezvous_; // A safepoint rendezvous request is in progress.
+ intptr_t remaining_; // Number of threads yet to reach their safepoint.
+ int64_t round_; // Counter, to prevent missing updates to remaining_
+ // (see comments in CheckSafepointLocked).
DISALLOW_COPY_AND_ASSIGN(ThreadRegistry);
};
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index f781783..d1db1d3 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -14,10 +14,8 @@
UNIT_TEST_CASE(Mutex) {
// This unit test case needs a running isolate.
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
Mutex* mutex = new Mutex();
mutex->Lock();
@@ -31,18 +29,16 @@
}
// The isolate shutdown and the destruction of the mutex are out-of-order on
// purpose.
- isolate->Shutdown();
- delete isolate;
+ Dart_ShutdownIsolate();
delete mutex;
}
UNIT_TEST_CASE(Monitor) {
// This unit test case needs a running isolate.
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ Isolate* isolate = Isolate::Current();
// Thread interrupter interferes with this test, disable interrupts.
isolate->set_thread_state(NULL);
Profiler::EndExecution(isolate);
@@ -79,8 +75,7 @@
// The isolate shutdown and the destruction of the mutex are out-of-order on
// purpose.
- isolate->Shutdown();
- delete isolate;
+ Dart_ShutdownIsolate();
delete monitor;
}
@@ -109,11 +104,10 @@
class TaskWithZoneAllocation : public ThreadPool::Task {
public:
TaskWithZoneAllocation(Isolate* isolate,
- const String& foo,
Monitor* monitor,
bool* done,
intptr_t id)
- : isolate_(isolate), foo_(foo), monitor_(monitor), done_(done), id_(id) {}
+ : isolate_(isolate), monitor_(monitor), done_(done), id_(id) {}
virtual void Run() {
Thread::EnterIsolateAsHelper(isolate_);
{
@@ -129,9 +123,10 @@
a0->Add(true);
a1.Add(true);
}
- // Check that we can create handles (but not yet allocate heap objects).
- String& str = String::Handle(zone, foo_.raw());
- EXPECT(str.Equals("foo"));
+ // Check that we can create handles and allocate in old space.
+ String& str = String::Handle(zone, String::New("old", Heap::kOld));
+ EXPECT(str.Equals("old"));
+
const intptr_t unique_smi = id_ + 928327281;
Smi& smi = Smi::Handle(zone, Smi::New(unique_smi));
EXPECT(smi.Value() == unique_smi);
@@ -140,6 +135,22 @@
// TODO(koda): Remove "->thread_registry()" after updating stack walker.
isolate_->thread_registry()->VisitObjectPointers(&counter);
EXPECT_EQ(1, counter.count());
+
+ char* unique_chars = zone->PrintToString("unique_str_%" Pd, id_);
+ String& unique_str = String::Handle(zone);
+ {
+ // String::New may create additional handles in the topmost scope that
+ // we don't want to count, so wrap this in its own scope.
+ HANDLESCOPE(thread);
+ unique_str = String::New(unique_chars, Heap::kOld);
+ }
+ EXPECT(unique_str.Equals(unique_chars));
+ ObjectCounter str_counter(isolate_, &unique_str);
+ // Ensure that our particular zone is visited.
+ // TODO(koda): Remove "->thread_registry()" after updating stack walker.
+ isolate_->thread_registry()->VisitObjectPointers(&str_counter);
+ // We should visit the string object exactly once.
+ EXPECT_EQ(1, str_counter.count());
}
Thread::ExitIsolateAsHelper();
{
@@ -151,7 +162,6 @@
private:
Isolate* isolate_;
- const String& foo_;
Monitor* monitor_;
bool* done_;
intptr_t id_;
@@ -163,12 +173,12 @@
Monitor sync[kTaskCount];
bool done[kTaskCount];
Isolate* isolate = Thread::Current()->isolate();
- String& foo = String::Handle(String::New("foo"));
-
+ EXPECT(isolate->heap()->GrowthControlState());
+ isolate->heap()->DisableGrowthControl();
for (int i = 0; i < kTaskCount; i++) {
done[i] = false;
Dart::thread_pool()->Run(
- new TaskWithZoneAllocation(isolate, foo, &sync[i], &done[i], i));
+ new TaskWithZoneAllocation(isolate, &sync[i], &done[i], i));
}
for (int i = 0; i < kTaskCount; i++) {
// Check that main mutator thread can still freely use its own zone.
@@ -195,18 +205,15 @@
Zone* orig_zone = Thread::Current()->zone();
char* orig_str = orig_zone->PrintToString("foo");
Thread::ExitIsolate();
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isos[2];
// Create and enter a new isolate.
- isos[0] = Isolate::Init(NULL, api_flags);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
Zone* zone0 = Thread::Current()->zone();
EXPECT(zone0 != orig_zone);
- isos[0]->Shutdown();
- Thread::ExitIsolate();
+ Dart_ShutdownIsolate();
// Create and enter yet another isolate.
- isos[1] = Isolate::Init(NULL, api_flags);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
{
// Create a stack resource this time, and exercise it.
StackZone stack_zone(Thread::Current());
@@ -214,14 +221,220 @@
EXPECT(zone1 != zone0);
EXPECT(zone1 != orig_zone);
}
- isos[1]->Shutdown();
- Thread::ExitIsolate();
+ Dart_ShutdownIsolate();
Thread::EnterIsolate(orig);
// Original zone should be preserved.
EXPECT_EQ(orig_zone, Thread::Current()->zone());
EXPECT_STREQ("foo", orig_str);
- delete isos[0];
- delete isos[1];
+}
+
+
+// A helper thread that alternatingly cooperates and organizes
+// safepoint rendezvous. At rendezvous, it explicitly visits the
+// stacks looking for a specific marker (Smi) to verify that the expected
+// number threads are actually visited. The task is "done" when it has
+// successfully made all other tasks and the main thread rendezvous (may
+// not happen in the first rendezvous, since tasks are still starting up).
+class SafepointTestTask : public ThreadPool::Task {
+ public:
+ static const intptr_t kTaskCount;
+
+ SafepointTestTask(Isolate* isolate,
+ Mutex* mutex,
+ intptr_t* expected_count,
+ intptr_t* total_done,
+ intptr_t* exited)
+ : isolate_(isolate),
+ mutex_(mutex),
+ expected_count_(expected_count),
+ total_done_(total_done),
+ exited_(exited),
+ local_done_(false) {}
+
+ virtual void Run() {
+ Thread::EnterIsolateAsHelper(isolate_);
+ {
+ MutexLocker ml(mutex_);
+ ++*expected_count_;
+ }
+ for (int i = 0; ; ++i) {
+ Thread* thread = Thread::Current();
+ StackZone stack_zone(thread);
+ Zone* zone = thread->zone();
+ HANDLESCOPE(thread);
+ const intptr_t kUniqueSmi = 928327281;
+ Smi& smi = Smi::Handle(zone, Smi::New(kUniqueSmi));
+ if ((i % 100) != 0) {
+ // Usually, we just cooperate.
+ isolate_->thread_registry()->CheckSafepoint();
+ } else {
+ // But occasionally, organize a rendezvous.
+ isolate_->thread_registry()->SafepointThreads();
+ ObjectCounter counter(isolate_, &smi);
+ isolate_->thread_registry()->VisitObjectPointers(&counter);
+ {
+ MutexLocker ml(mutex_);
+ EXPECT_EQ(*expected_count_, counter.count());
+ }
+ UserTag& tag = UserTag::Handle(zone, isolate_->current_tag());
+ if (tag.raw() != isolate_->default_tag()) {
+ String& label = String::Handle(zone, tag.label());
+ EXPECT(label.Equals("foo"));
+ MutexLocker ml(mutex_);
+ if (*expected_count_ == kTaskCount && !local_done_) {
+ // Success for the first time! Remember that we are done, and
+ // update the total count.
+ local_done_ = true;
+ ++*total_done_;
+ }
+ }
+ isolate_->thread_registry()->ResumeAllThreads();
+ }
+ // Check whether everyone is done.
+ {
+ MutexLocker ml(mutex_);
+ if (*total_done_ == kTaskCount) {
+ // Another task might be at SafepointThreads when resuming. Ensure its
+ // expectation reflects reality, since we pop our handles here.
+ --*expected_count_;
+ break;
+ }
+ }
+ }
+ Thread::ExitIsolateAsHelper();
+ {
+ MutexLocker ml(mutex_);
+ ++*exited_;
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ Mutex* mutex_;
+ intptr_t* expected_count_; // # copies of kUniqueSmi we expect to visit.
+ intptr_t* total_done_; // # tasks that successfully safepointed once.
+ intptr_t* exited_; // # tasks that are no longer running.
+ bool local_done_; // this task has successfully safepointed >= once.
+};
+
+
+const intptr_t SafepointTestTask::kTaskCount = 5;
+
+
+// Test rendezvous of:
+// - helpers in VM code,
+// - main thread in pure Dart,
+// organized by
+// - helpers.
+TEST_CASE(SafepointTestDart) {
+ Isolate* isolate = Thread::Current()->isolate();
+ Mutex mutex;
+ intptr_t expected_count = 0;
+ intptr_t total_done = 0;
+ intptr_t exited = 0;
+ for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
+ Dart::thread_pool()->Run(new SafepointTestTask(
+ isolate, &mutex, &expected_count, &total_done, &exited));
+ }
+ // Run Dart code on the main thread long enough to allow all helpers
+ // to get their verification done and exit. Use a specific UserTag
+ // to enable the helpers to verify that the main thread is
+ // successfully interrupted in the pure Dart loop.
+#if defined(USING_SIMULATOR)
+ const intptr_t kLoopCount = 12345678;
+#else
+ const intptr_t kLoopCount = 1234567890;
+#endif // USING_SIMULATOR
+ char buffer[1024];
+ OS::SNPrint(buffer, sizeof(buffer),
+ "import 'dart:profiler';\n"
+ "int dummy = 0;\n"
+ "main() {\n"
+ " new UserTag('foo').makeCurrent();\n"
+ " for (dummy = 0; dummy < %" Pd "; ++dummy) {\n"
+ " dummy += (dummy & 1);\n"
+ " }\n"
+ "}\n", kLoopCount);
+ Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
+ EXPECT_VALID(lib);
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ // Ensure we looped long enough to allow all helpers to succeed and exit.
+ {
+ MutexLocker ml(&mutex);
+ EXPECT_EQ(SafepointTestTask::kTaskCount, total_done);
+ EXPECT_EQ(SafepointTestTask::kTaskCount, exited);
+ }
+}
+
+
+// Test rendezvous of:
+// - helpers in VM code, and
+// - main thread in VM code,
+// organized by
+// - helpers.
+TEST_CASE(SafepointTestVM) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Mutex mutex;
+ intptr_t expected_count = 0;
+ intptr_t total_done = 0;
+ intptr_t exited = 0;
+ for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
+ Dart::thread_pool()->Run(new SafepointTestTask(
+ isolate, &mutex, &expected_count, &total_done, &exited));
+ }
+ String& label = String::Handle(String::New("foo"));
+ UserTag& tag = UserTag::Handle(UserTag::New(label));
+ isolate->set_current_tag(tag);
+ while (true) {
+ isolate->thread_registry()->CheckSafepoint();
+ MutexLocker ml(&mutex);
+ if (exited == SafepointTestTask::kTaskCount) {
+ break;
+ }
+ }
+}
+
+
+// Test rendezvous of:
+// - helpers in VM code, and
+// - main thread in VM code,
+// organized by
+// - main thread, and
+// - helpers.
+TEST_CASE(SafepointTestVM2) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Mutex mutex;
+ intptr_t expected_count = 0;
+ intptr_t total_done = 0;
+ intptr_t exited = 0;
+ for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
+ Dart::thread_pool()->Run(new SafepointTestTask(
+ isolate, &mutex, &expected_count, &total_done, &exited));
+ }
+ bool all_helpers = false;
+ do {
+ isolate->thread_registry()->SafepointThreads();
+ {
+ MutexLocker ml(&mutex);
+ if (expected_count == SafepointTestTask::kTaskCount) {
+ all_helpers = true;
+ }
+ }
+ isolate->thread_registry()->ResumeAllThreads();
+ } while (!all_helpers);
+ String& label = String::Handle(String::New("foo"));
+ UserTag& tag = UserTag::Handle(UserTag::New(label));
+ isolate->set_current_tag(tag);
+ while (true) {
+ isolate->thread_registry()->CheckSafepoint();
+ MutexLocker ml(&mutex);
+ if (exited == SafepointTestTask::kTaskCount) {
+ break;
+ }
+ }
}
} // namespace dart
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 3d5e179..4c3fb9b 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -197,12 +197,12 @@
obj.AddProperty("cat", stream_->name());
obj.AddProperty64("tid", tid);
obj.AddProperty64("pid", pid);
- obj.AddProperty("ts", static_cast<double>(TimeOrigin()));
+ obj.AddPropertyTimeMillis("ts", TimeOrigin());
switch (event_type()) {
case kDuration: {
obj.AddProperty("ph", "X");
- obj.AddProperty("dur", static_cast<double>(TimeDuration()));
+ obj.AddPropertyTimeMillis("dur", TimeDuration());
}
break;
case kInstant: {
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 88b8cb2..52dc222 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -335,8 +335,10 @@
'port.cc',
'port.h',
'port_test.cc',
- 'proccpuinfo.h',
+ 'precompiler.cc',
+ 'precompiler.h',
'proccpuinfo.cc',
+ 'proccpuinfo.h',
'profiler_service.cc',
'profiler_service.h',
'profiler_test.cc',
@@ -452,6 +454,7 @@
'thread_pool.cc',
'thread_pool.h',
'thread_pool_test.cc',
+ 'thread_registry.cc',
'thread_registry.h',
'thread_test.cc',
'timeline.cc',
diff --git a/runtime/vm/zone_test.cc b/runtime/vm/zone_test.cc
index 580f968..da5f208 100644
--- a/runtime/vm/zone_test.cc
+++ b/runtime/vm/zone_test.cc
@@ -16,11 +16,9 @@
#if defined(DEBUG)
FLAG_trace_zones = true;
#endif
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT(Isolate::Current() == isolate);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ Isolate* isolate = Isolate::Current();
EXPECT(isolate->current_zone() == NULL);
{
StackZone stack_zone(isolate);
@@ -72,8 +70,7 @@
EXPECT_LE(allocated_size, zone->SizeInBytes());
}
EXPECT(isolate->current_zone() == NULL);
- isolate->Shutdown();
- delete isolate;
+ Dart_ShutdownIsolate();
}
@@ -81,11 +78,9 @@
#if defined(DEBUG)
FLAG_trace_zones = true;
#endif
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT(Isolate::Current() == isolate);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ Isolate* isolate = Isolate::Current();
EXPECT(isolate->current_zone() == NULL);
{
StackZone zone(isolate);
@@ -98,8 +93,7 @@
EXPECT_LE(allocated_size, zone.SizeInBytes());
}
EXPECT(isolate->current_zone() == NULL);
- isolate->Shutdown();
- delete isolate;
+ Dart_ShutdownIsolate();
}
@@ -108,11 +102,9 @@
#if defined(DEBUG)
FLAG_trace_zones = true;
#endif
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT(Isolate::Current() == isolate);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ Isolate* isolate = Isolate::Current();
EXPECT(isolate->current_zone() == NULL);
{
StackZone zone(isolate);
@@ -121,8 +113,7 @@
const intptr_t kNumElements = (kIntptrMax / sizeof(uint32_t)) + 1;
zone.GetZone()->Alloc<uint32_t>(kNumElements);
}
- isolate->Shutdown();
- delete isolate;
+ Dart_ShutdownIsolate();
}
@@ -130,11 +121,9 @@
#if defined(DEBUG)
FLAG_trace_zones = true;
#endif
- Isolate::Flags vm_flags;
- Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
- Isolate* isolate = Isolate::Init(NULL, api_flags);
- EXPECT(Isolate::Current() == isolate);
+ Dart_CreateIsolate(
+ NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
+ Isolate* isolate = Isolate::Current();
EXPECT(isolate->current_zone() == NULL);
static int marker;
@@ -172,8 +161,7 @@
EXPECT_EQ(87, second->slot);
}
EXPECT(isolate->current_zone() == NULL);
- isolate->Shutdown();
- delete isolate;
+ Dart_ShutdownIsolate();
}
diff --git a/sdk/lib/_internal/js_runtime/lib/annotations.dart b/sdk/lib/_internal/js_runtime/lib/annotations.dart
index ee33493..2862612 100644
--- a/sdk/lib/_internal/js_runtime/lib/annotations.dart
+++ b/sdk/lib/_internal/js_runtime/lib/annotations.dart
@@ -56,3 +56,6 @@
/// Annotation that marks the declaration as a patch for the lazy emitter.
const _Patch patch_lazy = const _Patch('lazy');
+
+/// Annotation that marks the declaration as a patch for the startup emitter.
+const _Patch patch_startup = const _Patch('startup');
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 2ec85f0..971b37f 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -8,6 +8,7 @@
import 'dart:_js_helper' show patch,
patch_full,
patch_lazy,
+ patch_startup,
checkInt,
getRuntimeType,
jsonEncodeNative,
@@ -73,7 +74,15 @@
static apply(Function function,
List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
- return Primitives.applyFunctionNewEmitter(function, positionalArguments,
+ return Primitives.applyFunction2(function, positionalArguments,
+ namedArguments == null ? null : _symbolMapToStringMap(namedArguments));
+ }
+
+ @patch_startup
+ static apply(Function function,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ return Primitives.applyFunction2(function, positionalArguments,
namedArguments == null ? null : _symbolMapToStringMap(namedArguments));
}
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index a6087a1..4f06174d 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -7,26 +7,28 @@
import 'dart:_js_helper' show patch;
import 'dart:_foreign_helper' show JS;
-/// If [when] is true, stop the program as if a breakpoint where hit at the
-/// following statement. Returns the value of [when]. Some debuggers may
-/// display [msg].
-/// NOTE: When invoked, the isolate will not return until a debugger
-/// continues execution. When running in the Dart VM the behaviour is the same
-/// regardless of whether or not a debugger is connected. When compiled to
-/// JavaScript, this uses the "debugger" statement, and behaves exactly as
-/// that does.
@patch
@ForceInline()
-bool debugger({bool when: true, String msg}) {
+bool debugger({bool when: true, String message}) {
if (when) {
JS('', 'debugger');
}
return when;
}
-/// Send a reference to [object] to any attached debuggers so they may open an
-/// inspector on the object. Returns the argument.
@patch
-inspect(object) {
+Object inspect(Object object) {
return object;
}
+
+@patch
+log(String message,
+ {DateTime time,
+ int sequenceNumber,
+ int level: 0,
+ String name: '',
+ Zone zone,
+ Object error,
+ StackTrace stackTrace}) {
+ // TODO.
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
index 5ff44bb..b8a44b4 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
@@ -9,9 +9,9 @@
CLASS_FIELDS_EXTRACTOR,
CREATE_NEW_ISOLATE,
CURRENT_SCRIPT,
- GLOBAL_FUNCTIONS,
INITIALIZE_EMPTY_INSTANCE,
- INSTANCE_FROM_CLASS_ID;
+ INSTANCE_FROM_CLASS_ID,
+ STATIC_FUNCTION_NAME_PROPERTY_NAME;
import 'dart:async';
import 'dart:collection' show Queue;
@@ -24,6 +24,7 @@
Null,
Primitives,
convertDartClosureToJS,
+ createDartClosureFromNameOfStaticFunction,
isDartObject,
random64,
requiresPreamble;
@@ -103,6 +104,7 @@
throw new ArgumentError("Arguments to main must be a List: $args");
}
_globalState = new _Manager(entry);
+ _globalState._initialize();
// Don't start the main loop again, if we are in a worker.
if (_globalState.isWorker) return;
@@ -220,7 +222,9 @@
/** The entry point given by [startRootIsolate]. */
final Function entry;
- _Manager(this.entry) {
+ _Manager(this.entry);
+
+ _initialize() {
_nativeDetectEnvironment();
topEventLoop = new _EventLoop();
isolates = new Map<int, _IsolateContext>();
@@ -235,6 +239,8 @@
bool isWindowDefined = globalWindow != null;
bool isWorkerDefined = globalWorker != null;
+ // `isWorker` must be initialized now, since `IsolateNatives.thisScript`
+ // may access it.
isWorker = !isWindowDefined && globalPostMessageDefined;
supportsWorkers = isWorker
|| (isWorkerDefined && IsolateNatives.thisScript != null);
@@ -764,6 +770,8 @@
}
// A worker has no script tag - so get an url from a stack-trace.
if (_globalState.isWorker) return computeThisScriptFromTrace();
+ // An isolate that doesn't support workers, but doesn't have a
+ // currentScript either. This is most likely a Chrome extension.
return null;
}
@@ -904,8 +912,7 @@
}
static _getJSFunctionFromName(String functionName) {
- var globalFunctionsContainer = JS_EMBEDDED_GLOBAL("", GLOBAL_FUNCTIONS);
- return JS("", "#[#]()", globalFunctionsContainer, functionName);
+ return createDartClosureFromNameOfStaticFunction(functionName);
}
/**
@@ -914,7 +921,9 @@
* but you should probably not count on this.
*/
static String _getJSFunctionName(Function f) {
- return (f is Closure) ? JS("String|Null", r'#.$name', f) : null;
+ return (f is Closure)
+ ? JS("String|Null", r'#[#]', f, STATIC_FUNCTION_NAME_PROPERTY_NAME)
+ : null;
}
/** Create a new JavaScript object instance given its constructor. */
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index dda551e..fd53e61 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -19,7 +19,8 @@
JsBuiltin,
JsGetName,
LEAF_TAGS,
- NATIVE_SUPERCLASS_TAG_NAME;
+ NATIVE_SUPERCLASS_TAG_NAME,
+ STATIC_FUNCTION_NAME_PROPERTY_NAME;
import 'dart:collection';
@@ -188,6 +189,16 @@
JsBuiltin.getType, index);
}
+/// Returns a Dart closure for the global function with the given [name].
+///
+/// The [name] is the globally unique (minified) JavaScript name of the
+/// function. The name must be in correspondence with the propertyName that is
+/// used when creating a tear-off (see [fromTearOff]).
+Function createDartClosureFromNameOfStaticFunction(String name) {
+ return JS_BUILTIN('returns:Function',
+ JsBuiltin.createDartClosureFromNameOfStaticFunction, name);
+}
+
/// No-op method that is called to inform the compiler that preambles might
/// be needed when executing the resulting JS file in a command-line
/// JS engine.
@@ -1145,64 +1156,180 @@
namedArgumentList));
}
- static applyFunctionNewEmitter(Function function,
- List positionalArguments,
- Map<String, dynamic> namedArguments) {
- if (namedArguments == null) {
- int requiredParameterCount = JS('int', r'#[#]', function,
- JS_GET_NAME(JsGetName.REQUIRED_PARAMETER_PROPERTY));
- int argumentCount = positionalArguments.length;
- if (argumentCount < requiredParameterCount) {
- return functionNoSuchMethod(function, positionalArguments, null);
+ /**
+ * Implements [Function.apply] for the lazy and startup emitters.
+ *
+ * There are two types of closures that can reach this function:
+ *
+ * 1. tear-offs (including tear-offs of static functions).
+ * 2. anonymous closures.
+ *
+ * They are treated differently (although there are lots of similarities).
+ * Both have in common that they have
+ * a [JsGetName.CALL_CATCH_ALL] and
+ * a [JsGetName.REQUIRED_PARAMETER_PROPERTY] property.
+ *
+ * If the closure supports optional parameters, then they also feature
+ * a [JsGetName.DEFAULT_VALUES_PROPERTY] property.
+ *
+ * The catch-all property is a method that takes all arguments (including
+ * all optional positional or named arguments). If the function accepts
+ * optional arguments, then the default-values property stores (potentially
+ * wrapped in a function) the default values for the optional arguments. If
+ * the function accepts optional positional arguments, then the value is a
+ * JavaScript array with the default values. Otherwise, when the function
+ * accepts optional named arguments, it is a JavaScript object.
+ *
+ * The default-values property may either contain the value directly, or
+ * it can be a function that returns the default-values when invoked.
+ *
+ * If the function is an anonymous closure, then the catch-all property
+ * only contains a string pointing to the property that should be used
+ * instead. For example, if the catch-all property contains the string
+ * "call$4", then the object's "call$4" property should be used as if it was
+ * the value of the catch-all property.
+ */
+ static applyFunction2(Function function,
+ List positionalArguments,
+ Map<String, dynamic> namedArguments) {
+ // Fast shortcut for the common case.
+ if (JS('bool', '# instanceof Array', positionalArguments) &&
+ (namedArguments == null || namedArguments.isEmpty)) {
+ // Let the compiler know that we did a type-test.
+ List arguments = (JS('JSArray', '#', positionalArguments));
+ int argumentCount = arguments.length;
+ if (argumentCount == 0) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX0);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#]()', function, selectorName);
+ }
+ } else if (argumentCount == 1) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX1);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0])', function, selectorName, arguments);
+ }
+ } else if (argumentCount == 2) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX2);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1])', function, selectorName,
+ arguments, arguments);
+ }
+ } else if (argumentCount == 3) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX3);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
+ arguments, arguments, arguments);
+ }
}
String selectorName =
'${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount';
var jsStub = JS('var', r'#[#]', function, selectorName);
- if (jsStub == null) {
- // Do a dynamic call.
- var interceptor = getInterceptor(function);
- var jsFunction = JS('', '#[#]', interceptor,
- JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
- var defaultValues = JS('var', r'#[#]', function,
- JS_GET_NAME(JsGetName.DEFAULT_VALUES_PROPERTY));
- if (!JS('bool', '# instanceof Array', defaultValues)) {
- // The function expects named arguments!
- return functionNoSuchMethod(function, positionalArguments, null);
- }
- int defaultsLength = JS('int', "#.length", defaultValues);
- int maxArguments = requiredParameterCount + defaultsLength;
- if (argumentCount > maxArguments) {
- // The function expects less arguments!
- return functionNoSuchMethod(function, positionalArguments, null);
- }
- List arguments = new List.from(positionalArguments);
- List missingDefaults = JS('JSArray', '#.slice(#)', defaultValues,
- argumentCount - requiredParameterCount);
- arguments.addAll(missingDefaults);
- return JS('var', '#.apply(#, #)', jsFunction, function, arguments);
+ if (jsStub != null) {
+ return JS('var', '#.apply(#, #)', jsStub, function, arguments);
}
- return JS('var', '#.apply(#, #)', jsStub, function, positionalArguments);
+ }
+
+ return _genericApplyFunction2(
+ function, positionalArguments, namedArguments);
+ }
+
+ static _genericApplyFunction2(Function function,
+ List positionalArguments,
+ Map<String, dynamic> namedArguments) {
+ List arguments;
+ if (positionalArguments != null) {
+ if (JS('bool', '# instanceof Array', positionalArguments)) {
+ arguments = JS('JSArray', '#', positionalArguments);
+ } else {
+ arguments = new List.from(positionalArguments);
+ }
} else {
- var interceptor = getInterceptor(function);
- var jsFunction = JS('', '#[#]', interceptor,
- JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
- var defaultValues = JS('JSArray', r'#[#]', function,
+ arguments = [];
+ }
+
+ int argumentCount = arguments.length;
+
+ int requiredParameterCount = JS('int', r'#[#]', function,
+ JS_GET_NAME(JsGetName.REQUIRED_PARAMETER_PROPERTY));
+
+ if (argumentCount < requiredParameterCount) {
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ var defaultValuesClosure = JS('var', r'#[#]', function,
JS_GET_NAME(JsGetName.DEFAULT_VALUES_PROPERTY));
- List keys = JS('JSArray', r'Object.keys(#)', defaultValues);
- List arguments = new List.from(positionalArguments);
- int used = 0;
- for (String key in keys) {
- var value = namedArguments[key];
- if (value != null) {
- used++;
- arguments.add(value);
- } else {
- arguments.add(JS('var', r'#[#]', defaultValues, key));
- }
+
+ bool acceptsOptionalArguments = defaultValuesClosure != null;
+
+ // Default values are stored inside a JavaScript closure to avoid
+ // accessing them too early.
+ var defaultValues = acceptsOptionalArguments
+ ? JS('', '#()', defaultValuesClosure)
+ : null;
+
+ var interceptor = getInterceptor(function);
+ var jsFunction = JS('', '#[#]', interceptor,
+ JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
+ if (jsFunction is String) {
+ // Anonymous closures redirect to the catch-all property instead of
+ // storing the catch-all method directly in the catch-all property.
+ jsFunction = JS('', '#[#]', interceptor, jsFunction);
+ }
+
+ if (!acceptsOptionalArguments) {
+ if (argumentCount == requiredParameterCount) {
+ return JS('var', r'#.apply(#, #)', jsFunction, function, arguments);
}
- if (used != namedArguments.length) {
- return functionNoSuchMethod(function, positionalArguments,
- namedArguments);
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ bool acceptsPositionalArguments =
+ JS('bool', '# instanceof Array', defaultValues);
+
+ if (acceptsPositionalArguments) {
+ if (namedArguments != null && namedArguments.isNotEmpty) {
+ // Tried to invoke a function that takes optional positional arguments
+ // with named arguments.
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ int defaultsLength = JS('int', "#.length", defaultValues);
+ int maxArguments = requiredParameterCount + defaultsLength;
+ if (argumentCount > maxArguments) {
+ // The function expects fewer arguments.
+ return functionNoSuchMethod(function, arguments, null);
+ }
+ List missingDefaults = JS('JSArray', '#.slice(#)', defaultValues,
+ argumentCount - requiredParameterCount);
+ arguments.addAll(missingDefaults);
+ return JS('var', '#.apply(#, #)', jsFunction, function, arguments);
+ } else {
+ // Handle named arguments.
+
+ if (argumentCount > requiredParameterCount) {
+ // Tried to invoke a function that takes named parameters with
+ // too many positional arguments.
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ List keys = JS('JSArray', r'Object.keys(#)', defaultValues);
+ if (namedArguments == null) {
+ for (String key in keys) {
+ arguments.add(JS('var', '#[#]', defaultValues, key));
+ }
+ } else {
+ int used = 0;
+ for (String key in keys) {
+ if (namedArguments.containsKey(key)) {
+ used++;
+ arguments.add(namedArguments[key]);
+ } else {
+ arguments.add(JS('var', r'#[#]', defaultValues, key));
+ }
+ }
+ if (used != namedArguments.length) {
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
}
return JS('var', r'#.apply(#, #)', jsFunction, function, arguments);
}
@@ -2213,8 +2340,11 @@
*
* In other words, creates a tear-off closure.
*
+ * The [propertyName] argument is used by
+ * [JsBuiltin.createDartClosureFromNameOfStaticFunction].
+ *
* Called from [closureFromTearOff] as well as from reflection when tearing
- * of a method via [:getField:].
+ * of a method via `getField`.
*
* This method assumes that [functions] was created by the JavaScript function
* `addStubs` in `reflection_data_parser.dart`. That is, a list of JavaScript
@@ -2316,7 +2446,8 @@
trampoline = forwardCallTo(receiver, function, isIntercepted);
JS('', '#.\$reflectionInfo = #', trampoline, reflectionInfo);
} else {
- JS('', '#.\$name = #', prototype, propertyName);
+ JS('', '#[#] = #',
+ prototype, STATIC_FUNCTION_NAME_PROPERTY_NAME, propertyName);
}
var signatureFunction;
@@ -2629,7 +2760,8 @@
class StaticClosure extends TearOffClosure {
String toString() {
- String name = JS('String|Null', '#.\$name', this);
+ String name =
+ JS('String|Null', '#[#]', this, STATIC_FUNCTION_NAME_PROPERTY_NAME);
if (name == null) return "Closure of unknown static method";
return "Closure '$name'";
}
diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
index e99810a..9b44116c 100644
--- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -82,8 +82,8 @@
static makeNative(
String source, bool multiLine, bool caseSensitive, bool global) {
checkString(source);
- String m = multiLine ? 'm' : '';
- String i = caseSensitive ? '' : 'i';
+ String m = multiLine == true ? 'm' : '';
+ String i = caseSensitive == true ? '' : 'i';
String g = global ? 'g' : '';
// We're using the JavaScript's try catch instead of the Dart one
// to avoid dragging in Dart runtime support just because of using
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index a427996..b08e3a3 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -41,6 +41,12 @@
/// native class.
const NATIVE_SUPERCLASS_TAG_NAME = r"$nativeSuperclassTag";
+/// The name of the static-function property name.
+///
+/// This property is set for all tear-offs of static functions, and provides
+/// the static function's unique (potentially minified) name.
+const STATIC_FUNCTION_NAME_PROPERTY_NAME = r'$static_name';
+
/// The name of the embedded global for metadata.
///
@@ -54,10 +60,6 @@
/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
const TYPES = 'types';
-/// An embedded global name that can be used to store a mapping from
-/// static function names to dart-closure getters.
-const GLOBAL_FUNCTIONS = 'globalFunctions';
-
/// Returns a function that maps a name of a class to its type.
///
/// This embedded global is used by the runtime when computing the internal
@@ -77,8 +79,10 @@
/// A JS map from mangled instance names to their unmangled names.
///
-/// If the program does not use reflection, this embedded global may be empty
-/// (but not null or undefined).
+/// This embedded global is mainly used for reflection, but is also used to
+/// map const-symbols (`const Symbol('x')`) to the mangled instance names.
+///
+/// This embedded global may be empty (but not null or undefined).
const MANGLED_NAMES = 'mangledNames';
/// A JS map from dispatch tags (usually constructor names of DOM classes) to
@@ -235,11 +239,30 @@
const PRECOMPILED = 'precompiled';
/// An emitter-internal embedded global. This global is not used by the runtime.
+const FINISHED_CLASSES = 'finishedClasses';
+
+/// An emitter-internal embedded global. This global is not used by the runtime.
///
/// The constant remains in this file to make sure that other embedded globals
/// don't clash with it.
-const FINISHED_CLASSES = 'finishedClasses';
+///
+/// It can be used by the compiler to store a mapping from static function names
+/// to dart-closure getters (which can be useful for
+/// [JsBuiltin.createDartClosureFromNameOfStaticFunction].
+const GLOBAL_FUNCTIONS = 'globalFunctions';
+/// An emitter-internal embedded global. This global is not used by the runtime.
+///
+/// The constant remains in this file to make sure that other embedded globals
+/// don't clash with it.
+///
+/// This embedded global stores a function that returns a dart-closure getter
+/// for a given static function name.
+///
+/// This embedded global is used to implement
+/// [JsBuiltin.createDartClosureFromNameOfStaticFunction], and is only
+/// used with isolates.
+const STATIC_FUNCTION_NAME_TO_CLOSURE = 'staticFunctionNameToClosure';
/// A JavaScript object literal that maps the (minified) JavaScript constructor
/// name (as given by [JsBuiltin.rawRtiToJsConstructorName] to the
@@ -258,6 +281,7 @@
/// This embedded global is only used by reflection.
const STATICS = 'statics';
+
/// An array of library descriptors.
///
/// The descriptor contains information such as name, uri, classes, ...
@@ -391,4 +415,16 @@
/// JS_BUILTIN('returns:var;effects:none;depends:none',
/// JsBuiltin.getType, index);
getType,
+
+ /// Returns a Dart closure for the global function with the given [name].
+ ///
+ /// The [name] is the globally unique (minified) JavaScript name of the
+ /// function (same as the one stored in [STATIC_FUNCTION_NAME_PROPERTY_NAME])
+ ///
+ /// This builtin is used when a static closure was sent to a different
+ /// isolate.
+ ///
+ /// JS_BUILTIN('returns:Function',
+ /// JsBuiltin.createDartClosureFromNameOfStaticFunction, name);
+ createDartClosureFromNameOfStaticFunction,
}
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 428e878..6eb737e 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -842,7 +842,7 @@
* the returned stream is listened to.
*/
Stream<T> take(int count) {
- return new _TakeStream(this, count);
+ return new _TakeStream<T>(this, count);
}
/**
@@ -864,7 +864,7 @@
* the returned stream is listened to.
*/
Stream<T> takeWhile(bool test(T element)) {
- return new _TakeWhileStream(this, test);
+ return new _TakeWhileStream<T>(this, test);
}
/**
@@ -875,7 +875,7 @@
* the returned stream is listened to.
*/
Stream<T> skip(int count) {
- return new _SkipStream(this, count);
+ return new _SkipStream<T>(this, count);
}
/**
@@ -891,7 +891,7 @@
* the returned stream is listened to.
*/
Stream<T> skipWhile(bool test(T element)) {
- return new _SkipWhileStream(this, test);
+ return new _SkipWhileStream<T>(this, test);
}
/**
@@ -908,7 +908,7 @@
* will individually perform the `equals` test.
*/
Stream<T> distinct([bool equals(T previous, T next)]) {
- return new _DistinctStream(this, equals);
+ return new _DistinctStream<T>(this, equals);
}
/**
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 26bbb14..f856b61 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -639,8 +639,8 @@
throw new StateError("Stream has already been listened to.");
}
_ControllerSubscription subscription =
- new _ControllerSubscription(this, onData, onError, onDone,
- cancelOnError);
+ new _ControllerSubscription<T>(this, onData, onError, onDone,
+ cancelOnError);
_PendingEvents pendingEvents = _pendingEvents;
_state |= _STATE_SUBSCRIBED;
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 19bdb69..c23b0f0 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -512,7 +512,7 @@
bool cancelOnError) {
if (_isUsed) throw new StateError("Stream has already been listened to.");
_isUsed = true;
- return new _BufferingStreamSubscription(
+ return new _BufferingStreamSubscription<T>(
onData, onError, onDone, cancelOnError).._setPendingEvents(_pending());
}
}
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index 03c75c1..97c449e 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.dart
@@ -11,24 +11,42 @@
///
library dart.developer;
+import 'dart:async';
import 'dart:convert';
part 'profiler.dart';
/// If [when] is true, stop the program as if a breakpoint were hit at the
/// following statement.
-///
-/// Returns the value of [when]. Some debuggers may
-/// display [msg].
-///
+///
+/// Returns the value of [when]. Some debuggers may display [message].
+///
/// NOTE: When invoked, the isolate will not return until a debugger
/// continues execution. When running in the Dart VM the behaviour is the same
/// regardless of whether or not a debugger is connected. When compiled to
/// JavaScript, this uses the "debugger" statement, and behaves exactly as
/// that does.
-external bool debugger({bool when: true, String msg});
+external bool debugger({bool when: true, String message});
/// Send a reference to [object] to any attached debuggers.
-///
+///
/// Debuggers may open an inspector on the object. Returns the argument.
-external inspect(object);
+external Object inspect(Object object);
+
+/// Emit a log event.
+/// [message] is the log message.
+/// [time] (optional) is the timestamp.
+/// [sequenceNumber] (optional) is a monotonically increasing sequence number.
+/// [level] (optional) is the severity level (value between 0 and 2000).
+/// [name] (optional) is the name of the source of the log message.
+/// [zone] (optional) the zone where the log was emitted
+/// [error] (optional) an error object associated with this log event.
+/// [stackTrace] (optional) a stack trace associated with this log event.
+external log(String message,
+ {DateTime time,
+ int sequenceNumber,
+ int level: 0,
+ String name: '',
+ Zone zone,
+ Object error,
+ StackTrace stackTrace});
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index 78c15fa..89cd586 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.dart
@@ -273,18 +273,7 @@
}
void write(Object obj) {
- // This comment is copied from runtime/lib/string_buffer_patch.dart.
- // TODO(srdjan): The following four lines could be replaced by
- // '$obj', but apparently this is too slow on the Dart VM.
- String string;
- if (obj is String) {
- string = obj;
- } else {
- string = obj.toString();
- if (string is! String) {
- throw new ArgumentError('toString() did not return a string');
- }
- }
+ String string = '$obj';
if (string.isEmpty) return;
add(_encoding.encode(string));
}
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index 9ad7b56..56ddea0 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -53,9 +53,9 @@
* String os = Platform.operatingSystem;
* // Or, use a predicate getter.
* if (Platform.isMacOS) {
- * Print('is a Mac');
+ * print('is a Mac');
* } else {
- * print('is not a Mac');
+ * print('is not a Mac');
* }
* }
*
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 9693873..cc68544 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -888,7 +888,7 @@
if (_readyState == WebSocket.OPEN) {
_readyState = WebSocket.CLOSING;
if (!_isReservedStatusCode(transformer.closeCode)) {
- _close(transformer.closeCode);
+ _close(transformer.closeCode, transformer.closeReason);
} else {
_close();
}
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index f18e7f4..2e60ccc 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -13,6 +13,9 @@
[ $runtime == vm || $runtime != vm ]
# Tests that fail everywhere, including the analyzer.
+# No longer correct, y#$ now has a meaning. github.com/dart-lang/co19/issues/2
+Language/12_Expressions/30_Identifier_Reference_A01_t03: Skip
+
LibTest/typed_data/ByteData/buffer_A01_t01: Fail # co19 r736 bug - sent comment.
LayoutTests/fast/mediastream/getusermedia_t01: Fail # co19 issue 738.
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 59d8942c..3434fcf 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -101,75 +101,48 @@
LibTest/typed_data/ByteData/*Int64*: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/*Uint64*: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/ByteData.view_A01_t02: fail # co19-roll r569: Please triage this failure
-LibTest/typed_data/ByteData/ByteData.view_A01_t02: fail # co19-roll r569: Please triage this failure
-LibTest/typed_data/ByteData/ByteData.view_A03_t01: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/ByteData.view_A03_t01: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/ByteData.view_A04_t01: fail # co19-roll r569: Please triage this failure
-LibTest/typed_data/ByteData/ByteData.view_A04_t01: fail # co19-roll r569: Please triage this failure
-LibTest/typed_data/ByteData/ByteData.view_A05_t01: fail # Issue 12989
LibTest/typed_data/ByteData/ByteData.view_A05_t01: fail # Issue 12989
LibTest/typed_data/ByteData/ByteData.view_A05_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/ByteData.view_A05_t02: fail # Issue 12989
LibTest/typed_data/ByteData/ByteData.view_A05_t03: fail # Issue 12989
-LibTest/typed_data/ByteData/ByteData.view_A05_t03: fail # Issue 12989
-LibTest/typed_data/ByteData/ByteData_A01_t01: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/ByteData_A01_t01: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/ByteData_A02_t01: fail # co19-roll r576: Please triage this failure
LibTest/typed_data/ByteData/getFloat32_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getFloat32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getFloat32_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getFloat64_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getFloat64_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getFloat64_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getInt16_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getInt16_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getInt16_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getInt32_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getInt32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getInt32_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getInt64_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getInt8_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getInt8_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getInt8_A02_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/getInt8_A02_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/getUint16_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getUint16_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getUint16_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getUint32_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getUint32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getUint32_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getUint64_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/getUint8_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/getUint8_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/getUint8_A02_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/getUint8_A02_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/setFloat32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setFloat32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setFloat32_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setFloat64_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setFloat64_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setFloat64_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setInt16_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setInt16_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setInt16_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setInt32_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setInt32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setInt32_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setInt64_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setInt8_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setInt8_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setInt8_A02_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/setInt8_A02_t02: fail # Issue 12989
-LibTest/typed_data/ByteData/setUint16_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setUint16_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setUint16_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setUint32_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setUint32_A02_t01: fail # Issue 12989
LibTest/typed_data/ByteData/setUint32_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setUint64_A02_t02: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/setUint8_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setUint8_A02_t01: fail # Issue 12989
-LibTest/typed_data/ByteData/setUint8_A02_t02: fail # Issue 12989
LibTest/typed_data/ByteData/setUint8_A02_t02: fail # Issue 12989
LibTest/typed_data/Float32List/Float32List.view_A05_t01: RuntimeError # co19-roll r559: Please triage this failure
LibTest/typed_data/Float32List/Float32List.view_A05_t02: RuntimeError # co19-roll r559: Please triage this failure
@@ -235,6 +208,7 @@
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.
WebPlatformTest/dom/nodes/Element-childElementCount-nochild_t01: CompileTimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/webstorage/storage_session_setitem_quotaexceedederr_t01: Pass, Slow
LayoutTests/fast/loader/loadInProgress_t01: Skip # Issue 23466
LayoutTests/fast/dom/css-innerHTML_t01: SkipByDesign # Test is incorrect.
@@ -459,7 +433,6 @@
LayoutTests/fast/url/scheme_t01: RuntimeError
LayoutTests/fast/url/host-lowercase-per-scheme_t01: RuntimeError
LayoutTests/fast/url/safari-extension_t01: RuntimeError
-LayoutTests/fast/url/safari-extension_t01: RuntimeError
LayoutTests/fast/url/port_t01: RuntimeError
LayoutTests/fast/url/mailto_t01: RuntimeError
LayoutTests/fast/url/path-url_t01: RuntimeError
@@ -557,7 +530,6 @@
[ $compiler == dart2js && $runtime == chromeOnAndroid ]
Language/12_Expressions/00_Object_Identity/1_Object_Identity_A05_t02: RuntimeError # Please triage this failure.
Language/12_Expressions/05_Strings_A06_t01: Pass, Slow # Please triage this failure.
-Language/12_Expressions/05_Strings_A06_t01: Pass, Slow # Please triage this failure.
LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t01: Fail # Issue 22200.
LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t05: Fail # Issue 22200.
LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t06: Fail # Issue 22200.
@@ -714,13 +686,22 @@
LayoutTests/fast/css/add-remove-stylesheets-at-once-minimal-recalc-style_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/aspect-ratio-inheritance_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/aspect-ratio-parsing-tests_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/auto-min-size_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/checked-pseudo-selector_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/collapsed-whitespace-reattach-in-style-recalc_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/content-language-case-insensitivity_t01: RuntimeError # Issue 23506
+LayoutTests/fast/css/content-language-dynamically-added_t01: RuntimeError # Issue 23506
+LayoutTests/fast/css/content-language-dynamically-removed_t01: RuntimeError # Issue 23506
+LayoutTests/fast/css/content-language-mapped-to-webkit-locale_t01: RuntimeError # Issue 23506
+LayoutTests/fast/css/content-language-multiple_t01: RuntimeError # Issue 23506
+LayoutTests/fast/css/content-language-no-content_t01: RuntimeError # Issue 23506
LayoutTests/fast/css/content/content-none_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/content/content-normal_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/counters/complex-before_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/counters/counter-cssText_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/css-properties-case-insensitive_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/css3-nth-tokens-style_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/csstext-of-content-string_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/cursor-parsing-quirks_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/deprecated-flexbox-auto-min-size_t01: RuntimeError # Please triage this failure
@@ -734,9 +715,13 @@
LayoutTests/fast/css/font-face-unicode-range-overlap-load_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/fontfaceset-events_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/fontfaceset-loadingdone_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/getComputedStyle/computed-style-properties_t01: RuntimeError # Issue 23506
+LayoutTests/fast/css/getComputedStyle/counterIncrement-without-counter_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/html-attr-case-sensitivity_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/id-or-class-before-stylesheet_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/image-set-setting_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/implicit-attach-marking_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/css/important-js-override_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/inherit-initial-shorthand-values_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-predefined-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/link-alternate-stylesheet-1_t01: RuntimeError # Please triage this failure
@@ -746,9 +731,13 @@
LayoutTests/fast/css/link-alternate-stylesheet-5_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/media-query-recovery_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/modify-ua-rules-from-javascript_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/nested-at-rules_t01: RuntimeError # Issue 23506
LayoutTests/fast/css/parsing-at-rule-recovery_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/parsing-css-allowed-string-characters_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/parsing-css-nth-child_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/parsing-page-rule_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/parsing-selector-error-recovery_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/parsing-text-rendering_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/pseudo-any_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/pseudo-target-indirect-sibling-001_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css/pseudo-target-indirect-sibling-002_t01: Skip # Times out. Please triage this failure
@@ -760,6 +749,7 @@
LayoutTests/fast/css/readonly-pseudoclass-opera-005_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/shadow-current-color_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css/sticky/parsing-position-sticky_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/string-quote-binary_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/style-element-process-crash_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css/style-scoped/style-scoped-nested_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/style-scoped/style-scoped-with-dom-operation_t01: RuntimeError # Please triage this failure
@@ -855,9 +845,11 @@
LayoutTests/fast/dom/Window/window-scroll-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/anchor-without-content_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/attribute-namespaces-get-set_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/background-shorthand-csstext_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/blur-contenteditable_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/css-selectorText_t01: RuntimeError # Please triage this 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/dataset-xhtml_t01: RuntimeError # Please triage this failure
@@ -877,6 +869,7 @@
LayoutTests/fast/dom/option-properties_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/partial-layout-overlay-scrollbars_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/set-innerHTML_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/shadow/content-reprojection-fallback-crash_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/no-renderers-for-light-children_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/pseudoclass-update-checked-option_t01: RuntimeError # Please triage this failure
@@ -887,6 +880,7 @@
LayoutTests/fast/dom/shadow/shadow-content-crash_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/shadow-disable_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/shadow-removechild-and-blur-event_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/dom/shadow/shadow-root-js-api_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/shadowhost-keyframes_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/shadowroot-keyframes_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dynamic/crash-generated-counter_t01: RuntimeError # Please triage this failure
@@ -969,6 +963,7 @@
LayoutTests/fast/forms/setrangetext_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/textarea-paste-newline_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/textfield-focus-out_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/forms/validationMessage_t01: RuntimeError # Please triage this failure
LayoutTests/fast/html/hidden-attr_t01: RuntimeError # Please triage this failure
LayoutTests/fast/html/imports/import-element-removed-flag_t01: RuntimeError # Please triage this failure
LayoutTests/fast/html/imports/import-events_t01: RuntimeError # Please triage this failure
@@ -979,6 +974,7 @@
LayoutTests/fast/inline/out-of-flow-objects-and-whitespace-after-empty-inline_t01: RuntimeError # Please triage this failure
LayoutTests/fast/inline/parent-inline-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
LayoutTests/fast/inline/positioned-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Please triage this failure
LayoutTests/fast/layers/normal-flow-hit-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/layers/zindex-hit-test_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/loader/about-blank-hash-change_t01: Skip # Times out. Please triage this failure
@@ -1213,7 +1209,6 @@
LibTest/html/Node/parent_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Node/previousNode_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/animationFrame_A01_t01: Skip # Times out. Please triage this failure
-LibTest/html/Window/close_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/document_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/find_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/find_A03_t01: RuntimeError # Please triage this failure
@@ -1283,11 +1278,13 @@
WebPlatformTest/html/dom/elements/global-attributes/dataset-set_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/document-metadata/styling/LinkStyle_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/embedded-content/media-elements/error-codes/error_t01: Skip # Times out. Please triage this failure
+WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/addTextTrack_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/src_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/cues_t01: Skip # Times out. Please triage this failure
WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/mode_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/attributes-common-to-form-controls/formAction_document_address_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/attributes-common-to-form-controls/formaction_t01: RuntimeError # Please triage this failure
+WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setRangeText_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange_t01: Pass, RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/the-button-element/button-validation_t01: RuntimeError # Please triage this failure
@@ -1309,6 +1306,7 @@
WebPlatformTest/html/semantics/forms/the-input-element/time_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/the-input-element/time_t02: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/the-input-element/type-change-state_t01: RuntimeError # Please triage this failure
+WebPlatformTest/html/semantics/forms/the-input-element/url_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/the-input-element/valueMode_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/the-input-element/week_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/the-meter-element/meter_t01: RuntimeError # Please triage this failure
@@ -1346,6 +1344,9 @@
WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-element-interface/attributes/test-004_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-element-interface/attributes/test-004_t02: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-element-interface/methods/elements-001_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-event-interface/event-path-001_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-002_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-005_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/elements-and-dom-objects/the-content-html-element/test-004_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/elements-and-dom-objects/the-content-html-element/test-004_t02: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/elements-and-dom-objects/the-content-html-element/test-006_t01: RuntimeError # Please triage this failure
@@ -1372,6 +1373,7 @@
WebPlatformTest/shadow-dom/shadow-trees/distributed-pseudo-element/test-001_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/shadow-trees/distributed-pseudo-element/test-002_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/shadow-trees/lower-boundary-encapsulation/test-004_t01: RuntimeError # Please triage this failure
+WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-002_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-009_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/event_constructor_t01: RuntimeError # Please triage this failure
@@ -1379,7 +1381,6 @@
WebPlatformTest/webstorage/storage_local_setitem_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/storage_session_setitem_t01: RuntimeError # Please triage this failure
-
[ $compiler == dart2js && $runtime == chrome && $checked ]
LayoutTests/fast/css-intrinsic-dimensions/css-tables_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-absolutes_t01: RuntimeError # Please triage this failure
@@ -1451,36 +1452,17 @@
WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # Please triage this failure
WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-001_t01: RuntimeError # Please triage this failure
-[ $compiler == dart2js && $runtime == chrome && ($system == windows || $system == macos) ]
-# New failures on Chrome 43, linux bots are not yet at that version.
-LayoutTests/fast/css/content-language-case-insensitivity_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/content-language-dynamically-removed_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/content-language-dynamically-added_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/content-language-no-content_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/content-language-multiple_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/content-language-mapped-to-webkit-locale_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/getComputedStyle/computed-style-properties_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/nested-at-rules_t01: RuntimeError # Issue 23506
-LayoutTests/fast/css/getComputedStyle/counterIncrement-without-counter_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/image-set-setting_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/parsing-text-rendering_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/background-shorthand-csstext_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/addTextTrack_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/semantics/forms/the-input-element/url_t01: RuntimeError # Please triage this failure
-WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-event-interface/event-path-001_t01: RuntimeError # Please triage this failure
-
[ $compiler == dart2js && $runtime == chrome && $system == macos ]
LayoutTests/fast/canvas/webgl/canvas-test_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/canvas/webgl/draw-webgl-to-canvas-2d_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/dom/MutationObserver/observe-attributes_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/multicol/newmulticol/balance_t04: RuntimeError # Please triage this failure
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-different-writing-modes-left_t01: RuntimeError # Please triage this failure
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-rounded-boxes_t02: RuntimeError # Please triage this failure
LayoutTests/fast/text/glyph-reordering_t01: RuntimeError # Please triage this failure
LayoutTests/fast/text/line-break-after-question-mark_t01: RuntimeError # Please triage this failure
LayoutTests/fast/text/text-combine-shrink-to-fit_t01: RuntimeError # Please triage this failure
+LibTest/async/Timer/Timer.periodic_A01_t01: Skip # Times out. Please triage this failure
[ $compiler == dart2js && $runtime == chrome && $system != macos ]
LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Please triage this failure
@@ -3081,7 +3063,7 @@
WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-011_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/event_constructor_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/event_constructor_t02: RuntimeError # Please triage this failure
-WebPlatformTest/webstorage/storage_local_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure
+WebPlatformTest/webstorage/storage_local_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure. Note that Chrome also requires the Slow flag. (Could just be a slow test).
WebPlatformTest/webstorage/storage_local_setitem_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/storage_session_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure
WebPlatformTest/webstorage/storage_session_setitem_t01: RuntimeError # Please triage this failure
@@ -9071,6 +9053,7 @@
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-before-open_t01: RuntimeError # Please triage this failure
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-sync-request_t01: RuntimeError # Please triage this failure
LayoutTests/fast/xmlhttprequest/xmlhttprequest-set-responsetype_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/xmlhttprequest/xmlhttprequest-withcredentials-before-open_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/xpath/4XPath/Borrowed/cz_20030217_t01: RuntimeError # Please triage this failure
LayoutTests/fast/xpath/4XPath/Borrowed/kd_20010423_t01: RuntimeError # Please triage this failure
LayoutTests/fast/xpath/4XPath/Borrowed/namespace-nodes_t01: RuntimeError # Please triage this failure
@@ -9275,6 +9258,7 @@
LibTest/html/Window/resizeTo_A01_t01: RuntimeError # Please triage this failure
LibTest/math/sqrt_A02_t02: Skip # Times out. Please triage this failure
LibTest/typed_data/ByteData/ByteData.view_A01_t01: Pass, RuntimeError # Please triage this failure
+LibTest/typed_data/ByteData/offsetInBytes_A01_t01: RuntimeError # Please triage this failure
LibTest/typed_data/Float32List/removeWhere_A01_t01: Skip # Times out. Please triage this failure
LibTest/typed_data/Float32x4List/Float32x4List.view_A06_t01: RuntimeError # Please triage this failure
LibTest/typed_data/Int32List/lastWhere_A01_t01: Skip # Times out. Please triage this failure
@@ -9600,9 +9584,8 @@
Language/13_Statements/12_Labels_A03_t04: Crash # (switch (i){L:case 0:flag=true;break;case 2:continue L;}): continue to a labeled switch case
Language/13_Statements/14_Continue_A02_t12: Crash # (switch (2){L:case 1:flag=true;break;case 2:continue L;}): continue to a labeled switch case
Language/13_Statements/14_Continue_A02_t13: Crash # (switch (2){case 2:continue L;L:case 1:flag=true;}): continue to a labeled switch case
+Language/15_Types/4_Interface_Types_A12_t09: RuntimeError # Please triage this failure.
LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: Crash # (lazy.method()): deferred access is not implemented
-LibTest/collection/ListBase/ListBase_class_A01_t02: Crash # Stack Overflow
-LibTest/collection/ListMixin/ListMixin_class_A01_t02: Crash # Stack Overflow
LibTest/core/Invocation/isAccessor_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
LibTest/core/Invocation/isGetter_A01_t01: RuntimeError # Please triage this failure.
LibTest/core/Invocation/isGetter_A01_t02: RuntimeError # Please triage this failure.
@@ -9612,7 +9595,6 @@
LibTest/core/Invocation/memberName_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
LibTest/core/Invocation/namedArguments_A01_t01: RuntimeError # Please triage this failure.
LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # Please triage this failure.
-LibTest/core/List/List_class_A01_t02: Crash # Stack Overflow
LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Please triage this failure.
LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Please triage this failure.
LibTest/core/double/INFINITY_A01_t04: Pass # Please triage this failure.
diff --git a/tests/compiler/dart2js/analyze_helper.dart b/tests/compiler/dart2js/analyze_helper.dart
index 7636eb2..3ed51d4 100644
--- a/tests/compiler/dart2js/analyze_helper.dart
+++ b/tests/compiler/dart2js/analyze_helper.dart
@@ -96,10 +96,10 @@
}
@override
- void report(Uri uri, int begin, int end, String message,
+ void report(Message message, Uri uri, int begin, int end, String text,
api.Diagnostic kind) {
if (kind == api.Diagnostic.WARNING) {
- if (checkWhiteList(uri, message)) {
+ if (checkWhiteList(uri, text)) {
// Suppress whitelisted warnings.
lastWasWhitelisted = true;
return;
@@ -107,7 +107,7 @@
hasWarnings = true;
}
if (kind == api.Diagnostic.HINT) {
- if (checkWhiteList(uri, message)) {
+ if (checkWhiteList(uri, text)) {
// Suppress whitelisted hints.
lastWasWhitelisted = true;
return;
@@ -115,7 +115,7 @@
hasHint = true;
}
if (kind == api.Diagnostic.ERROR) {
- if (checkWhiteList(uri, message)) {
+ if (checkWhiteList(uri, text)) {
// Suppress whitelisted errors.
lastWasWhitelisted = true;
return;
@@ -126,7 +126,7 @@
return;
}
lastWasWhitelisted = false;
- super.report(uri, begin, end, message, kind);
+ super.report(message, uri, begin, end, text, kind);
}
}
diff --git a/tests/compiler/dart2js/analyze_only_test.dart b/tests/compiler/dart2js/analyze_only_test.dart
index 785d3f8..ff28085 100644
--- a/tests/compiler/dart2js/analyze_only_test.dart
+++ b/tests/compiler/dart2js/analyze_only_test.dart
@@ -12,8 +12,8 @@
import '../../utils/dummy_compiler_test.dart' as dummy;
import 'package:compiler/compiler.dart';
-import 'package:compiler/src/dart2jslib.dart' show
- MessageKind;
+import 'package:compiler/src/warnings.dart' show
+ MessageKind, MessageTemplate;
import 'output_collector.dart';
@@ -68,8 +68,10 @@
(String code, List errors, List warnings) {
Expect.isNotNull(code);
Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
+ MessageTemplate template =
+ MessageTemplate.TEMPLATES[MessageKind.MISSING_MAIN];
Expect.equals(
- "${MessageKind.MISSING_MAIN.message({'main': 'main'})}",
+ "${template.message({'main': 'main'})}",
warnings.single);
});
@@ -88,8 +90,10 @@
(String code, List errors, List warnings) {
Expect.isNull(code);
Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
+ MessageTemplate template =
+ MessageTemplate.TEMPLATES[MessageKind.CONSIDER_ANALYZE_ALL];
Expect.equals(
- "${MessageKind.CONSIDER_ANALYZE_ALL.message({'main': 'main'})}",
+ "${template.message({'main': 'main'})}",
warnings.single);
});
@@ -108,8 +112,10 @@
(String code, List errors, List warnings) {
Expect.isNull(code);
Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
+ MessageTemplate template =
+ MessageTemplate.TEMPLATES[MessageKind.CONSIDER_ANALYZE_ALL];
Expect.equals(
- "${MessageKind.CONSIDER_ANALYZE_ALL.message({'main': 'main'})}",
+ "${template.message({'main': 'main'})}",
warnings.single);
});
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
index db3923a..dc2aeef 100644
--- a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -47,6 +47,10 @@
"accept", "FunctionExpression", "CreateFunction"
],
+ "lib/src/universe/universe.dart": const [
+ "The method 'getterInvocationsByName' is never called.",
+ "The method 'setterInvocationsByName' is never called."],
+
"lib/src/cps_ir/": const [
"accept", "CreateFunction",
],
diff --git a/tests/compiler/dart2js/array_tracing_mirror_test.dart b/tests/compiler/dart2js/array_tracing_mirror_test.dart
index fe5324c..2c4c9aa 100644
--- a/tests/compiler/dart2js/array_tracing_mirror_test.dart
+++ b/tests/compiler/dart2js/array_tracing_mirror_test.dart
@@ -31,11 +31,12 @@
};
main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ var compiler = result.compiler;
var element = compiler.mainApp.findExported('main');
var code = compiler.backend.assembleCode(element);
Expect.isTrue(code.contains('return 2'));
- }));
+ });
}
diff --git a/tests/compiler/dart2js/bad_output_io_test.dart b/tests/compiler/dart2js/bad_output_io_test.dart
index ad2b0b9..7815b59 100644
--- a/tests/compiler/dart2js/bad_output_io_test.dart
+++ b/tests/compiler/dart2js/bad_output_io_test.dart
@@ -38,13 +38,13 @@
}
@override
- void report(Uri uri, int begin, int end, String message, kind) {
+ void report(var code, Uri uri, int begin, int end, String message, kind) {
messages.add([message, kind]);
}
@override
void call(Uri uri, int begin, int end, String message, kind) {
- report(uri, begin, end, message, kind);
+ report(null, uri, begin, end, message, kind);
}
String prefixMessage(String message, Diagnostic kind) {
diff --git a/tests/compiler/dart2js/check_elements_invariants_test.dart b/tests/compiler/dart2js/check_elements_invariants_test.dart
index 471cee4..bc1314f 100644
--- a/tests/compiler/dart2js/check_elements_invariants_test.dart
+++ b/tests/compiler/dart2js/check_elements_invariants_test.dart
@@ -3,13 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
+import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/apiimpl.dart';
import 'package:expect/expect.dart';
import 'package:compiler/src/elements/elements.dart'
show ClassElement;
import 'package:compiler/src/resolution/class_members.dart'
show ClassMemberMixin;
-import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart';
@@ -32,13 +32,12 @@
"Not all members have been computed for $cls.");
}
-Future checkElementInvariantsAfterCompiling(Uri uri) {
- var compiler = compilerFor({}, options: DART2JS_OPTIONS);
- return compiler.run(uri).then((passed) {
- Expect.isTrue(passed, "Compilation of dart2js failed.");
+Future checkElementInvariantsAfterCompiling(Uri uri) async {
+ CompilationResult result =
+ await runCompiler(entryPoint: uri, options: DART2JS_OPTIONS);
+ Expect.isTrue(result.isSuccess, "Compilation of dart2js failed.");
- computeLiveClasses(compiler).forEach(checkClassInvariants);
- });
+ computeLiveClasses(result.compiler).forEach(checkClassInvariants);
}
void main () {
diff --git a/tests/compiler/dart2js/class_set_test.dart b/tests/compiler/dart2js/class_set_test.dart
new file mode 100644
index 0000000..cd8abdd
--- /dev/null
+++ b/tests/compiler/dart2js/class_set_test.dart
@@ -0,0 +1,324 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for iterators on for [SubclassNode].
+
+library world_test;
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'type_test_helper.dart';
+import 'package:compiler/src/elements/elements.dart'
+ show Element, ClassElement;
+import 'package:compiler/src/dart2jslib.dart';
+import 'package:compiler/src/universe/class_set.dart';
+import 'package:compiler/src/util/util.dart';
+
+void main() {
+ asyncTest(() => TypeEnvironment.create(r"""
+ /// A
+ /// / \
+ /// B C
+ /// / /|\
+ /// D E F G
+ ///
+ class A {}
+ class B extends A {}
+ class C extends A {}
+ class D extends B {}
+ class E extends C {}
+ class F extends C {}
+ class G extends C {}
+ """,
+ mainSource: r"""
+ main() {
+ new A();
+ new C();
+ new D();
+ new E();
+ new F();
+ new G();
+ }
+ """,
+ useMockCompiler: false).then((env) {
+ World world = env.compiler.world;
+
+ ClassElement A = env.getElement("A");
+ ClassElement B = env.getElement("B");
+ ClassElement C = env.getElement("C");
+ ClassElement D = env.getElement("D");
+ ClassElement E = env.getElement("E");
+ ClassElement F = env.getElement("F");
+ ClassElement G = env.getElement("G");
+
+ void checkClass(ClassElement cls,
+ {bool directlyInstantiated: false,
+ bool indirectlyInstantiated: false}) {
+ ClassHierarchyNode node = world.classHierarchyNode(cls);
+ Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
+ Expect.equals(
+ directlyInstantiated || indirectlyInstantiated,
+ node.isInstantiated,
+ "Unexpected `isInstantiated` on ClassHierarchyNode for $cls.");
+ Expect.equals(
+ directlyInstantiated,
+ node.isDirectlyInstantiated,
+ "Unexpected `isDirectlyInstantiated` on ClassHierarchyNode for "
+ "$cls.");
+ Expect.equals(
+ indirectlyInstantiated,
+ node.isIndirectlyInstantiated,
+ "Unexpected `isIndirectlyInstantiated` on ClassHierarchyNode for "
+ "$cls.");
+ }
+
+
+ checkClass(A, directlyInstantiated: true, indirectlyInstantiated: true);
+ checkClass(B, indirectlyInstantiated: true);
+ checkClass(C, directlyInstantiated: true, indirectlyInstantiated: true);
+ checkClass(D, directlyInstantiated: true);
+ checkClass(E, directlyInstantiated: true);
+ checkClass(F, directlyInstantiated: true);
+ checkClass(G, directlyInstantiated: true);
+
+ ClassHierarchyNodeIterator iterator;
+
+ void checkState(
+ ClassElement root,
+ {ClassElement currentNode,
+ List<List<ClassElement>> stack}) {
+
+ ClassElement classOf(ClassHierarchyNode node) {
+ return node != null ? node.cls : null;
+ }
+
+ List<ClassElement> classesOf(Link<ClassHierarchyNode> link) {
+ if (link == null) return null;
+ return link.map(classOf).toList();
+ }
+
+ ClassElement foundRoot = iterator.root.cls;
+ ClassElement foundCurrentNode = classOf(iterator.currentNode);
+ List<ClassElement> foundStack = classesOf(iterator.stack);
+
+ StringBuffer sb = new StringBuffer();
+ sb.write('{\n root: $foundRoot');
+ sb.write('\n currentNode: $foundCurrentNode');
+ sb.write('\n stack: $foundStack\n}');
+
+ Expect.equals(root, foundRoot,
+ "Expected root $root in $sb.");
+ if (currentNode == null) {
+ Expect.isNull(iterator.currentNode,
+ "Unexpected non-null currentNode in $sb.");
+ } else {
+ Expect.isNotNull(foundCurrentNode,
+ "Expected non-null currentNode ${currentNode} in $sb.");
+ Expect.equals(currentNode, foundCurrentNode,
+ "Expected currentNode $currentNode in $sb.");
+ }
+ if (stack == null) {
+ Expect.isNull(foundStack,
+ "Unexpected non-null stack in $sb.");
+ } else {
+ Expect.isNotNull(foundStack,
+ "Expected non-null stack ${stack} in $sb.");
+ Expect.listEquals(stack, foundStack,
+ "Expected stack ${stack}, "
+ "found ${foundStack} in $sb.");
+ }
+ }
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(G)).iterator;
+ checkState(G, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(G, currentNode: G, stack: []);
+ Expect.equals(G, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(G, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(G), includeRoot: false).iterator;
+ checkState(G, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(G, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(C)).iterator;
+ checkState(C, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: C, stack: [E, F, G]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: E, stack: [F, G]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: F, stack: [G]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(C, currentNode: G, stack: []);
+ Expect.equals(G, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(C, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(D)).iterator;
+ checkState(D, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(D, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(D, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(B)).iterator;
+ checkState(B, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: B, stack: [D]);
+ Expect.equals(B, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(B, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(B), includeRoot: false).iterator;
+ checkState(B, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(B, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(B), directlyInstantiatedOnly: true).iterator;
+ checkState(B, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(B, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(B, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(A)).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: A, stack: [C, B]);
+ Expect.equals(A, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: B, stack: [D]);
+ Expect.equals(B, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(A), includeRoot: false).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: B, stack: [D]);
+ Expect.equals(B, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(A), directlyInstantiatedOnly: true).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: A, stack: [C, B]);
+ Expect.equals(A, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+
+ iterator = new ClassHierarchyNodeIterable(
+ world.classHierarchyNode(A),
+ includeRoot: false, directlyInstantiatedOnly: true).iterator;
+ checkState(A, currentNode: null, stack: null);
+ Expect.isNull(iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: C, stack: [E, F, G, B]);
+ Expect.equals(C, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: E, stack: [F, G, B]);
+ Expect.equals(E, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: F, stack: [G, B]);
+ Expect.equals(F, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: G, stack: [B]);
+ Expect.equals(G, iterator.current);
+ Expect.isTrue(iterator.moveNext());
+ checkState(A, currentNode: D, stack: []);
+ Expect.equals(D, iterator.current);
+ Expect.isFalse(iterator.moveNext());
+ checkState(A, currentNode: null, stack: []);
+ Expect.isNull(iterator.current);
+ }));
+}
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 90dd441..ce972e5 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -22,6 +22,7 @@
show Constant,
Message,
MessageKind,
+ MessageTemplate,
Selector,
TypedSelector,
SourceSpan,
diff --git a/tests/compiler/dart2js/compiler_test.dart b/tests/compiler/dart2js/compiler_test.dart
index 581489c..6e16da6 100644
--- a/tests/compiler/dart2js/compiler_test.dart
+++ b/tests/compiler/dart2js/compiler_test.dart
@@ -25,7 +25,8 @@
MessageKind messageKind,
[Map arguments = const {}]) {
if (onWarning != null) {
- onWarning(this, node, messageKind.message(arguments));
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+ onWarning(this, node, template.message(arguments));
}
super.reportWarning(node, messageKind, arguments);
}
@@ -34,7 +35,8 @@
MessageKind messageKind,
[Map arguments = const {}]) {
if (onError != null) {
- onError(this, node, messageKind.message(arguments));
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+ onError(this, node, template.message(arguments));
}
super.reportError(node, messageKind, arguments);
}
diff --git a/tests/compiler/dart2js/constant_expression_evaluate_test.dart b/tests/compiler/dart2js/constant_expression_evaluate_test.dart
index 94a0213e..fba3a20 100644
--- a/tests/compiler/dart2js/constant_expression_evaluate_test.dart
+++ b/tests/compiler/dart2js/constant_expression_evaluate_test.dart
@@ -10,7 +10,6 @@
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/constants/values.dart';
import 'package:compiler/src/constant_system_dart.dart';
-import 'package:compiler/src/core_types.dart';
import 'package:compiler/src/dart2jslib.dart';
import 'package:compiler/src/elements/elements.dart';
import 'memory_compiler.dart';
@@ -204,7 +203,7 @@
asyncTest(() => Future.forEach(DATA, testData));
}
-Future testData(TestData data) {
+Future testData(TestData data) async {
StringBuffer sb = new StringBuffer();
sb.write('${data.declarations}\n');
Map constants = {};
@@ -215,23 +214,22 @@
});
sb.write('main() {}\n');
String source = sb.toString();
- Compiler compiler = compilerFor(
- {'main.dart': source}, options: ['--analyze-all']);
- return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
- var library = compiler.mainApp;
- constants.forEach((String name, ConstantData data) {
- FieldElement field = library.localLookup(name);
- ConstantExpression constant = field.constant;
- data.expectedValues.forEach(
- (Map<String, String> env, String expectedText) {
- Environment environment = new MemoryEnvironment(compiler, env);
- ConstantValue value =
- constant.evaluate(environment, DART_CONSTANT_SYSTEM);
- String valueText = value.toStructuredString();
- Expect.equals(expectedText, valueText,
- "Unexpected value '${valueText}' for contant "
- "`${constant.getText()}`, expected '${expectedText}'.");
- });
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: {'main.dart': source}, options: ['--analyze-all']);
+ Compiler compiler = result.compiler;
+ var library = compiler.mainApp;
+ constants.forEach((String name, ConstantData data) {
+ FieldElement field = library.localLookup(name);
+ ConstantExpression constant = field.constant;
+ data.expectedValues.forEach(
+ (Map<String, String> env, String expectedText) {
+ Environment environment = new MemoryEnvironment(compiler, env);
+ ConstantValue value =
+ constant.evaluate(environment, DART_CONSTANT_SYSTEM);
+ String valueText = value.toStructuredString();
+ Expect.equals(expectedText, valueText,
+ "Unexpected value '${valueText}' for contant "
+ "`${constant.getText()}`, expected '${expectedText}'.");
});
});
}
diff --git a/tests/compiler/dart2js/constant_expression_test.dart b/tests/compiler/dart2js/constant_expression_test.dart
index d4e9df0..166a0ae 100644
--- a/tests/compiler/dart2js/constant_expression_test.dart
+++ b/tests/compiler/dart2js/constant_expression_test.dart
@@ -197,7 +197,7 @@
asyncTest(() => Future.forEach(DATA, testData));
}
-Future testData(TestData data) {
+Future testData(TestData data) async {
StringBuffer sb = new StringBuffer();
sb.write('${data.declarations}\n');
Map constants = {};
@@ -208,39 +208,39 @@
});
sb.write('main() {}\n');
String source = sb.toString();
- Compiler compiler = compilerFor(
- {'main.dart': source}, options: ['--analyze-all']);
- return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
- var library = compiler.mainApp;
- constants.forEach((String name, ConstantData data) {
- FieldElement field = library.localLookup(name);
- var constant = field.constant;
- Expect.equals(data.kind, constant.kind,
- "Unexpected kind '${constant.kind}' for contant "
- "`${constant.getText()}`, expected '${data.kind}'.");
- Expect.equals(data.text, constant.getText(),
- "Unexpected text '${constant.getText()}' for contant, "
- "expected '${data.text}'.");
- if (data.type != null) {
- String instanceType = constant.computeInstanceType().toString();
- Expect.equals(data.type, instanceType,
- "Unexpected type '$instanceType' for contant "
- "`${constant.getText()}`, expected '${data.type}'.");
- }
- if (data.fields != null) {
- Map instanceFields = constant.computeInstanceFields();
- Expect.equals(data.fields.length, instanceFields.length,
- "Unexpected field count ${instanceFields.length} for contant "
- "`${constant.getText()}`, expected '${data.fields.length}'.");
- instanceFields.forEach((field, expression) {
- String name = '$field';
- String expression = instanceFields[field].getText();
- String expected = data.fields[name];
- Expect.equals(expected, expression,
- "Unexpected field expression ${expression} for field '$name' in "
- "contant `${constant.getText()}`, expected '${expected}'.");
- });
- }
- });
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: {'main.dart': source},
+ options: ['--analyze-all']);
+ Compiler compiler = result.compiler;
+ var library = compiler.mainApp;
+ constants.forEach((String name, ConstantData data) {
+ FieldElement field = library.localLookup(name);
+ var constant = field.constant;
+ Expect.equals(data.kind, constant.kind,
+ "Unexpected kind '${constant.kind}' for contant "
+ "`${constant.getText()}`, expected '${data.kind}'.");
+ Expect.equals(data.text, constant.getText(),
+ "Unexpected text '${constant.getText()}' for contant, "
+ "expected '${data.text}'.");
+ if (data.type != null) {
+ String instanceType = constant.computeInstanceType().toString();
+ Expect.equals(data.type, instanceType,
+ "Unexpected type '$instanceType' for contant "
+ "`${constant.getText()}`, expected '${data.type}'.");
+ }
+ if (data.fields != null) {
+ Map instanceFields = constant.computeInstanceFields();
+ Expect.equals(data.fields.length, instanceFields.length,
+ "Unexpected field count ${instanceFields.length} for contant "
+ "`${constant.getText()}`, expected '${data.fields.length}'.");
+ instanceFields.forEach((field, expression) {
+ String name = '$field';
+ String expression = instanceFields[field].getText();
+ String expected = data.fields[name];
+ Expect.equals(expected, expression,
+ "Unexpected field expression ${expression} for field '$name' in "
+ "contant `${constant.getText()}`, expected '${expected}'.");
+ });
+ }
});
}
diff --git a/tests/compiler/dart2js/container_mask_equal_test.dart b/tests/compiler/dart2js/container_mask_equal_test.dart
index 28a7645..96834e9 100644
--- a/tests/compiler/dart2js/container_mask_equal_test.dart
+++ b/tests/compiler/dart2js/container_mask_equal_test.dart
@@ -27,8 +27,9 @@
};
main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ var compiler = result.compiler;
var typesInferrer = compiler.typesTask.typesInferrer;
var element = compiler.mainApp.find('a');
@@ -45,5 +46,5 @@
Expect.notEquals(mask1.union(mask2, compiler.world),
mask3.union(mask4, compiler.world));
- }));
+ });
}
diff --git a/tests/compiler/dart2js/deferred_custom_element_test.dart b/tests/compiler/dart2js/deferred_custom_element_test.dart
index 1fa5d12..b1f1b3e 100644
--- a/tests/compiler/dart2js/deferred_custom_element_test.dart
+++ b/tests/compiler/dart2js/deferred_custom_element_test.dart
@@ -12,8 +12,10 @@
import 'memory_compiler.dart';
void main() {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ Compiler compiler = result.compiler;
var outputUnitForElement = compiler.deferredLoadTask.outputUnitForElement;
var mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit;
var lib =
@@ -23,7 +25,7 @@
Expect.notEquals(mainOutputUnit, outputUnitForElement(foo));
// Native elements are not deferred
Expect.equals(mainOutputUnit, outputUnitForElement(customType));
- }));
+ });
}
// The main library imports a file defining a custom element.
diff --git a/tests/compiler/dart2js/deferred_dont_inline_deferred_constants_test.dart b/tests/compiler/dart2js/deferred_dont_inline_deferred_constants_test.dart
index 0cbcc0b..fa9753e 100644
--- a/tests/compiler/dart2js/deferred_dont_inline_deferred_constants_test.dart
+++ b/tests/compiler/dart2js/deferred_dont_inline_deferred_constants_test.dart
@@ -12,11 +12,13 @@
import 'output_collector.dart';
void main() {
- OutputCollector collector = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ asyncTest(() async {
+ OutputCollector collector = new OutputCollector();
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
outputProvider: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ Compiler compiler = result.compiler;
+
lookupLibrary(name) {
return compiler.libraryLoader.lookupLibrary(Uri.parse(name));
}
@@ -78,7 +80,7 @@
Expect.isTrue(new RegExp(r"= .string4").hasMatch(lib1Output));
Expect.isTrue(new RegExp(r"= .string4").hasMatch(lib2Output));
Expect.isFalse(new RegExp(r"= .string4").hasMatch(lib12Output));
- }));
+ });
}
// Make sure that deferred constants are not inlined into the main hunk.
diff --git a/tests/compiler/dart2js/deferred_dont_inline_deferred_globals_test.dart b/tests/compiler/dart2js/deferred_dont_inline_deferred_globals_test.dart
index 4f516e4..1a85a12 100644
--- a/tests/compiler/dart2js/deferred_dont_inline_deferred_globals_test.dart
+++ b/tests/compiler/dart2js/deferred_dont_inline_deferred_globals_test.dart
@@ -13,10 +13,11 @@
void main() {
OutputCollector collector = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
- outputProvider: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector);
+ Compiler compiler = result.compiler;
lookupLibrary(name) {
return compiler.libraryLoader.lookupLibrary(Uri.parse(name));
}
@@ -40,7 +41,7 @@
Expect.isTrue(re2.hasMatch(lib1Output));
Expect.isFalse(re1.hasMatch(mainOutput));
Expect.isFalse(re2.hasMatch(mainOutput));
- }));
+ });
}
// Make sure that deferred constants are not inlined into the main hunk.
diff --git a/tests/compiler/dart2js/deferred_emit_type_checks_test.dart b/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
index 3fe7752..2132fde 100644
--- a/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
+++ b/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
@@ -14,11 +14,12 @@
import 'output_collector.dart';
void main() {
- OutputCollector collector = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
- outputProvider: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ OutputCollector collector = new OutputCollector();
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector);
+ Compiler compiler = result.compiler;
String mainOutput = collector.getOutput('', 'js');
String deferredOutput = collector.getOutput('out_1', 'part.js');
JavaScriptBackend backend = compiler.backend;
@@ -27,7 +28,7 @@
"Deferred output doesn't contain '${isPrefix}A: 1':\n"
"$deferredOutput");
Expect.isFalse(mainOutput.contains('${isPrefix}A: 1'));
- }));
+ });
}
// We force additional runtime type support to be output for A by instantiating
diff --git a/tests/compiler/dart2js/deferred_follow_constant_dependencies_test.dart b/tests/compiler/dart2js/deferred_follow_constant_dependencies_test.dart
index e675f3f..7d2c686 100644
--- a/tests/compiler/dart2js/deferred_follow_constant_dependencies_test.dart
+++ b/tests/compiler/dart2js/deferred_follow_constant_dependencies_test.dart
@@ -11,8 +11,10 @@
import 'memory_compiler.dart';
void main() {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ Compiler compiler = result.compiler;
var outputUnitForElement = compiler.deferredLoadTask.outputUnitForElement;
var outputUnitForConstant = compiler.deferredLoadTask.outputUnitForConstant;
var mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit;
@@ -35,7 +37,7 @@
Expect.notEquals(null, outputUnitForConstant(constant));
Expect.notEquals(mainOutputUnit, outputUnitForConstant(constant));
}
- }));
+ });
}
// The main library imports lib1 and lib2 deferred and use lib1.foo1 and
diff --git a/tests/compiler/dart2js/deferred_follow_implicit_super_regression_test.dart b/tests/compiler/dart2js/deferred_follow_implicit_super_regression_test.dart
index a300eba..acd0146 100644
--- a/tests/compiler/dart2js/deferred_follow_implicit_super_regression_test.dart
+++ b/tests/compiler/dart2js/deferred_follow_implicit_super_regression_test.dart
@@ -3,23 +3,18 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
-import "package:async_helper/async_helper.dart";
-import 'memory_source_file_helper.dart';
-import "memory_compiler.dart";
-import "dart:async";
+import 'package:async_helper/async_helper.dart';
+import 'memory_compiler.dart';
import 'package:compiler/src/dart2jslib.dart'
as dart2js;
-runTest(String mainScript, test) {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES,
- outputProvider: new OutputCollector());
- asyncTest(() => compiler.run(Uri.parse(mainScript))
- .then((_) => test(compiler)));
-}
-
void main() {
- runTest('memory:main.dart', (compiler) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ dart2js.Compiler compiler = result.compiler;
+
lookupLibrary(name) {
return compiler.libraryLoader.lookupLibrary(Uri.parse(name));
}
diff --git a/tests/compiler/dart2js/deferred_inline_restrictions_test.dart b/tests/compiler/dart2js/deferred_inline_restrictions_test.dart
index 7ae382b..a750587 100644
--- a/tests/compiler/dart2js/deferred_inline_restrictions_test.dart
+++ b/tests/compiler/dart2js/deferred_inline_restrictions_test.dart
@@ -9,14 +9,15 @@
import 'package:compiler/src/dart2jslib.dart';
import 'package:expect/expect.dart';
import 'memory_compiler.dart';
-import 'output_collector.dart';
void main() {
- OutputCollector collector = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ asyncTest(() async {
+ OutputCollector collector = new OutputCollector();
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
outputProvider: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ Compiler compiler = result.compiler;
+
lookupLibrary(name) {
return compiler.libraryLoader.lookupLibrary(Uri.parse(name));
}
@@ -57,7 +58,7 @@
// Test that inlineSameContext was inlined into lib1.
Expect.isFalse(re4.hasMatch(lib3Output));
Expect.isTrue(re4.hasMatch(lib1Output));
- }));
+ });
}
// Make sure that empty functions are inlined and that functions from
diff --git a/tests/compiler/dart2js/deferred_load_graph_segmentation2_test.dart b/tests/compiler/dart2js/deferred_load_graph_segmentation2_test.dart
index 3467d2c..0b79a13 100644
--- a/tests/compiler/dart2js/deferred_load_graph_segmentation2_test.dart
+++ b/tests/compiler/dart2js/deferred_load_graph_segmentation2_test.dart
@@ -12,8 +12,10 @@
import 'memory_compiler.dart';
void main() {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ Compiler compiler = result.compiler;
var outputUnitForElement = compiler.deferredLoadTask.outputUnitForElement;
var mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit;
var lib =
@@ -22,7 +24,7 @@
var f2 = lib.find("f2");
Expect.notEquals(mainOutputUnit, outputUnitForElement(f1));
Expect.equals(mainOutputUnit, outputUnitForElement(f2));
- }));
+ });
}
// The main library imports lib1 and lib2 deferred and use lib1.foo1 and
diff --git a/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart b/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
index 59b39e3..1fa3534 100644
--- a/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
+++ b/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
@@ -13,8 +13,11 @@
import 'memory_compiler.dart';
void main() {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ Compiler compiler = result.compiler;
+
lookupLibrary(name) {
return compiler.libraryLoader.lookupLibrary(Uri.parse(name));
}
@@ -66,7 +69,7 @@
Expect.listEquals([ou_lib4_1], hunksLib4_1);
Expect.listEquals([ou_lib4_2], hunksLib4_2);
Expect.equals(hunksToLoad["main"], null);
- }));
+ });
}
// The main library imports lib1 and lib2 deferred and use lib1.foo1 and
diff --git a/tests/compiler/dart2js/deferred_load_mapping_test.dart b/tests/compiler/dart2js/deferred_load_mapping_test.dart
index 6877f4f..4cb51d13 100644
--- a/tests/compiler/dart2js/deferred_load_mapping_test.dart
+++ b/tests/compiler/dart2js/deferred_load_mapping_test.dart
@@ -8,26 +8,26 @@
import "memory_compiler.dart";
void main() {
- var collector = new OutputCollector();
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES,
- options: ['--deferred-map=deferred_map.json'],
- outputProvider: collector);
- asyncTest(() {
- return compiler.run(Uri.parse('memory:main.dart')).then((success) {
- // Ensure a mapping file is output.
- Expect.isNotNull(
- collector.getOutput("deferred_map.json", "deferred_map"));
+ asyncTest(() async {
+ var collector = new OutputCollector();
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ options: ['--deferred-map=deferred_map.json'],
+ outputProvider: collector);
+ Compiler compiler = result.compiler;
+ // Ensure a mapping file is output.
+ Expect.isNotNull(
+ collector.getOutput("deferred_map.json", "deferred_map"));
- Map mapping = compiler.deferredLoadTask.computeDeferredMap();
- // Test structure of mapping.
- Expect.equals("<unnamed>", mapping["main.dart"]["name"]);
- Expect.equals(2, mapping["main.dart"]["imports"]["lib1"].length);
- Expect.equals(2, mapping["main.dart"]["imports"]["lib2"].length);
- Expect.equals(1, mapping["main.dart"]["imports"]["convert"].length);
- Expect.equals("lib1", mapping["memory:lib1.dart"]["name"]);
- Expect.equals(1, mapping["memory:lib1.dart"]["imports"]["lib4_1"].length);
- Expect.equals(1, mapping["memory:lib2.dart"]["imports"]["lib4_2"].length);
- });
+ Map mapping = compiler.deferredLoadTask.computeDeferredMap();
+ // Test structure of mapping.
+ Expect.equals("<unnamed>", mapping["main.dart"]["name"]);
+ Expect.equals(2, mapping["main.dart"]["imports"]["lib1"].length);
+ Expect.equals(2, mapping["main.dart"]["imports"]["lib2"].length);
+ Expect.equals(1, mapping["main.dart"]["imports"]["convert"].length);
+ Expect.equals("lib1", mapping["memory:lib1.dart"]["name"]);
+ Expect.equals(1, mapping["memory:lib1.dart"]["imports"]["lib4_1"].length);
+ Expect.equals(1, mapping["memory:lib2.dart"]["imports"]["lib4_2"].length);
});
}
diff --git a/tests/compiler/dart2js/deferred_mirrors_test.dart b/tests/compiler/dart2js/deferred_mirrors_test.dart
index 4f38d5a..c92aaa1 100644
--- a/tests/compiler/dart2js/deferred_mirrors_test.dart
+++ b/tests/compiler/dart2js/deferred_mirrors_test.dart
@@ -6,19 +6,18 @@
// to determine which elements can be deferred and which libraries
// much be included in the initial download (loaded eagerly).
+import 'dart:async';
import 'package:expect/expect.dart';
-import "package:async_helper/async_helper.dart";
-import 'memory_source_file_helper.dart';
-import "memory_compiler.dart";
-
+import 'package:async_helper/async_helper.dart';
+import 'memory_compiler.dart';
import 'package:compiler/src/dart2jslib.dart'
as dart2js;
-runTest(String mainScript, test) {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES,
- outputProvider: new OutputCollector());
- asyncTest(() => compiler.run(Uri.parse(mainScript))
- .then((_) => test(compiler)));
+Future runTest(String mainScript, test) async {
+ CompilationResult result = await runCompiler(
+ entryPoint: Uri.parse(mainScript),
+ memorySourceFiles: MEMORY_SOURCE_FILES);
+ test(result.compiler);
}
lookupLibrary(compiler, name) {
@@ -26,7 +25,11 @@
}
void main() {
- runTest('memory:main.dart', (compiler) {
+ asyncTest(runTests);
+}
+
+runTests() async {
+ await runTest('memory:main.dart', (compiler) {
var main = compiler.mainApp.find(dart2js.Compiler.MAIN);
Expect.isNotNull(main, "Could not find 'main'");
compiler.deferredLoadTask.onResolutionComplete(main);
@@ -44,12 +47,12 @@
Expect.equals(outputUnitForElement(main), outputUnitForElement(sin));
Expect.equals(outputUnitForElement(foo2), outputUnitForElement(field2));
});
- runTest('memory:main2.dart', (compiler) {
+ await runTest('memory:main2.dart', (compiler) {
// Just check that the compile runs.
// This is a regression test.
Expect.isTrue(true);
});
- runTest('memory:main3.dart', (compiler) {
+ await runTest('memory:main3.dart', (compiler) {
var main = compiler.mainApp.find(dart2js.Compiler.MAIN);
Expect.isNotNull(main, "Could not find 'main'");
compiler.deferredLoadTask.onResolutionComplete(main);
@@ -64,7 +67,7 @@
Expect.notEquals(outputUnitForElement(main), outputUnitForElement(foo));
Expect.equals(outputUnitForElement(main), outputUnitForElement(C));
});
- runTest('memory:main4.dart', (compiler) {
+ await runTest('memory:main4.dart', (compiler) {
var main = compiler.mainApp.find(dart2js.Compiler.MAIN);
Expect.isNotNull(main, "Could not find 'main'");
compiler.deferredLoadTask.onResolutionComplete(main);
diff --git a/tests/compiler/dart2js/deferred_not_in_main_test.dart b/tests/compiler/dart2js/deferred_not_in_main_test.dart
index 0b8ef3a..002d9e5 100644
--- a/tests/compiler/dart2js/deferred_not_in_main_test.dart
+++ b/tests/compiler/dart2js/deferred_not_in_main_test.dart
@@ -12,8 +12,11 @@
import 'memory_compiler.dart';
void main() {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ Compiler compiler = result.compiler;
+
lookupLibrary(name) {
return compiler.libraryLoader.lookupLibrary(Uri.parse(name));
}
@@ -30,7 +33,7 @@
var foo2 = lib2.find("foo2");
Expect.notEquals(mainOutputUnit, outputUnitForElement(foo2));
- }));
+ });
}
// lib1 imports lib2 deferred. But mainlib never uses DeferredLibrary.
diff --git a/tests/compiler/dart2js/diagnose_ambiguous_test.dart b/tests/compiler/dart2js/diagnose_ambiguous_test.dart
index 9d96426..09e8706 100644
--- a/tests/compiler/dart2js/diagnose_ambiguous_test.dart
+++ b/tests/compiler/dart2js/diagnose_ambiguous_test.dart
@@ -5,17 +5,17 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/compiler_new.dart' show Diagnostic;
-import 'package:compiler/src/dart2jslib.dart';
import 'package:expect/expect.dart';
import 'memory_compiler.dart';
void main() {
DiagnosticCollector collector = new DiagnosticCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ asyncTest(() async {
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
diagnosticHandler: collector,
options: ['--analyze-all']);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+
List<String> diagnostics = <String>[];
collector.messages.forEach((DiagnosticMessage message) {
if (message.kind == Diagnostic.VERBOSE_INFO) return;
@@ -30,8 +30,8 @@
"memory:main.dart:86:92:Duplicate import of 'hest'.:warning",
];
Expect.listEquals(expected, diagnostics);
- Expect.isFalse(compiler.compilationFailed);
- }));
+ Expect.isTrue(result.isSuccess);
+ });
}
const Map MEMORY_SOURCE_FILES = const {
diff --git a/tests/compiler/dart2js/dictionary_types_test.dart b/tests/compiler/dart2js/dictionary_types_test.dart
index 7cea785..af56b54 100644
--- a/tests/compiler/dart2js/dictionary_types_test.dart
+++ b/tests/compiler/dart2js/dictionary_types_test.dart
@@ -103,51 +103,51 @@
"""};
void main() {
- asyncTest(() =>
- compileAndTest("AddAll.dart", (types, getType, compiler) {
+ asyncTest(() async {
+ await compileAndTest("AddAll.dart", (types, getType, compiler) {
Expect.equals(getType('int'), types.uint31Type);
Expect.equals(getType('anotherInt'), types.uint31Type);
Expect.equals(getType('dynamic'), types.dynamicType);
Expect.equals(getType('nullOrInt'), types.uint31Type.nullable());
- }));
- asyncTest(() => compileAndTest("Union.dart", (types, getType, compiler) {
- Expect.equals(getType('nullOrInt'), types.uint31Type.nullable());
- Expect.isTrue(getType('aString').containsOnlyString(compiler.world));
- Expect.equals(getType('doubleOrNull'), types.doubleType.nullable());
- }));
- asyncTest(() =>
- compileAndTest("ValueType.dart", (types, getType, compiler) {
+ });
+ await compileAndTest("Union.dart", (types, getType, compiler) {
+ Expect.equals(getType('nullOrInt'), types.uint31Type.nullable());
+ Expect.isTrue(getType('aString').containsOnlyString(compiler.world));
+ Expect.equals(getType('doubleOrNull'), types.doubleType.nullable());
+ });
+ await compileAndTest("ValueType.dart", (types, getType, compiler) {
Expect.equals(getType('knownDouble'), types.doubleType);
Expect.equals(getType('intOrNull'), types.uint31Type.nullable());
Expect.equals(getType('justNull'), types.nullType);
- }));
- asyncTest(() => compileAndTest("Propagation.dart", (code) {
- Expect.isFalse(code.contains("J.\$add\$ns"));
- }, createCode: true));
- asyncTest(() => compileAndTest("Bailout.dart", (types, getType, compiler) {
- Expect.equals(getType('notInt'), types.dynamicType);
- Expect.equals(getType('alsoNotInt'), types.dynamicType);
- Expect.isFalse(getType('dict').isDictionary);
- }));
+ });
+ await compileAndTest("Propagation.dart", (code) {
+ Expect.isFalse(code.contains("J.\$add\$ns"));
+ }, createCode: true);
+ await compileAndTest("Bailout.dart", (types, getType, compiler) {
+ Expect.equals(getType('notInt'), types.dynamicType);
+ Expect.equals(getType('alsoNotInt'), types.dynamicType);
+ Expect.isFalse(getType('dict').isDictionary);
+ });
+ });
}
-compileAndTest(source, checker, {createCode: false}) {
- var compiler = compilerFor(SOURCES);
- compiler.stopAfterTypeInference = !createCode;
- var uri = Uri.parse('memory:'+source);
- return compiler.runCompiler(uri).then((_) {
- var typesTask = compiler.typesTask;
- var typesInferrer = typesTask.typesInferrer;
- getType(String name) {
- var element = findElement(compiler, name);
- return typesInferrer.getTypeOfElement(element);
- }
- if (!createCode) {
- checker(typesTask, getType, compiler);
- } else {
- var element = compiler.mainApp.findExported('main');
- var code = compiler.backend.assembleCode(element);
- checker(code);
- }
- });
+compileAndTest(source, checker, {createCode: false}) async {
+ CompilationResult result = await runCompiler(
+ entryPoint: Uri.parse('memory:'+source),
+ memorySourceFiles: SOURCES,
+ beforeRun: (compiler) { compiler.stopAfterTypeInference = !createCode; });
+ var compiler = result.compiler;
+ var typesTask = compiler.typesTask;
+ var typesInferrer = typesTask.typesInferrer;
+ getType(String name) {
+ var element = findElement(compiler, name);
+ return typesInferrer.getTypeOfElement(element);
+ }
+ if (!createCode) {
+ checker(typesTask, getType, compiler);
+ } else {
+ var element = compiler.mainApp.findExported('main');
+ var code = compiler.backend.assembleCode(element);
+ checker(code);
+ }
}
diff --git a/tests/compiler/dart2js/dump_info_test.dart b/tests/compiler/dart2js/dump_info_test.dart
index bc962c2..c5da18c 100644
--- a/tests/compiler/dart2js/dump_info_test.dart
+++ b/tests/compiler/dart2js/dump_info_test.dart
@@ -97,26 +97,29 @@
typedef void JsonTaking(Map<String, dynamic> json);
-void jsonTest(String program, JsonTaking testFn) {
- var compiler = compilerFor({'main.dart': program}, options: ['--dump-info']);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then(
- (_) {
- Expect.isFalse(compiler.compilationFailed);
- var dumpTask = compiler.dumpInfoTask;
- dumpTask.collectInfo();
- var info = dumpTask.infoCollector;
+jsonTest(String program, JsonTaking testFn) async {
+ var result = await runCompiler(
+ memorySourceFiles: {'main.dart': program}, options: ['--dump-info']);
+ var compiler = result.compiler;
+ Expect.isFalse(compiler.compilationFailed);
+ var dumpTask = compiler.dumpInfoTask;
+ dumpTask.collectInfo();
+ var info = dumpTask.infoCollector;
- StringBuffer sb = new StringBuffer();
- dumpTask.dumpInfoJson(sb);
- String json = sb.toString();
- Map<String, dynamic> map = JSON.decode(json);
+ StringBuffer sb = new StringBuffer();
+ dumpTask.dumpInfoJson(sb);
+ String json = sb.toString();
+ Map<String, dynamic> map = JSON.decode(json);
- testFn(map);
- }));
+ testFn(map);
}
main() {
- jsonTest(TEST_BASIC, (map) {
+ asyncTest(runTests);
+}
+
+runTests() async {
+ await jsonTest(TEST_BASIC, (map) {
Expect.isTrue(map['elements'].isNotEmpty);
Expect.isTrue(map['elements']['function'].isNotEmpty);
Expect.isTrue(map['elements']['library'].isNotEmpty);
@@ -131,7 +134,7 @@
}));
});
- jsonTest(TEST_CLOSURES, (map) {
+ await jsonTest(TEST_CLOSURES, (map) {
var functions = map['elements']['function'].values;
Expect.isTrue(functions.any((fn) {
return fn['name'] == 'bar' && fn['children'].length == 11;
@@ -141,7 +144,7 @@
}));
});
- jsonTest(TEST_STATICS, (map) {
+ await jsonTest(TEST_STATICS, (map) {
var functions = map['elements']['function'].values;
var classes = map['elements']['class'].values;
Expect.isTrue(functions.any((fn) {
@@ -153,7 +156,7 @@
}));
});
- jsonTest(TEST_INLINED_1, (map) {
+ await jsonTest(TEST_INLINED_1, (map) {
var functions = map['elements']['function'].values;
var classes = map['elements']['class'].values;
Expect.isTrue(functions.any((fn) {
@@ -166,7 +169,7 @@
}));
});
- jsonTest(TEST_INLINED_2, (map) {
+ await jsonTest(TEST_INLINED_2, (map) {
var functions = map['elements']['function'].values;
var deps = map['holding'];
var main_ = functions.firstWhere((v) => v['name'] == 'main');
diff --git a/tests/compiler/dart2js/duplicate_library_test.dart b/tests/compiler/dart2js/duplicate_library_test.dart
index 43a1deb..8536370 100644
--- a/tests/compiler/dart2js/duplicate_library_test.dart
+++ b/tests/compiler/dart2js/duplicate_library_test.dart
@@ -5,41 +5,46 @@
// Test that duplicate library names result in different messages depending
// on whether the libraries are based on the same resource.
+import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
-
+import 'package:compiler/src/dart2jslib.dart' show MessageKind;
import 'memory_compiler.dart';
void check(String kind,
Iterable<DiagnosticMessage> messages,
- List<String> prefixes) {
- Expect.equals(messages.length, prefixes.length,
+ List<MessageKind> expectedMessageKinds) {
+ Expect.equals(messages.length, expectedMessageKinds.length,
"Unexpected $kind count: $messages");
int i = 0;
messages.forEach((DiagnosticMessage message) {
- Expect.isTrue(message.message.startsWith(prefixes[i++]));
+ Expect.equals(expectedMessageKinds[i++], message.message.kind);
});
}
-void test(Map<String, String> source,
- {List<String> warnings: const <String>[],
- List<String> hints: const <String>[]}) {
+Future test(Map<String, String> source,
+ {List<MessageKind> warnings: const <MessageKind>[],
+ List<MessageKind> hints: const <MessageKind>[]}) async {
DiagnosticCollector collector = new DiagnosticCollector();
- var compiler = compilerFor(source,
- diagnosticHandler: collector,
- showDiagnostics: true,
- options: ['--analyze-only', '--analyze-all'],
- packageRoot: Uri.parse('memory:pkg/'));
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
- Expect.isTrue(collector.errors.isEmpty);
- check('warning', collector.warnings, warnings);
- check('hint', collector.hints, hints);
- Expect.isTrue(collector.infos.isEmpty);
- }));
+ await runCompiler(
+ memorySourceFiles: source,
+ diagnosticHandler: collector,
+ showDiagnostics: true,
+ options: ['--analyze-only', '--analyze-all'],
+ packageRoot: Uri.parse('memory:pkg/'));
+
+ Expect.isTrue(collector.errors.isEmpty);
+ check('warning', collector.warnings, warnings);
+ check('hint', collector.hints, hints);
+ Expect.isTrue(collector.infos.isEmpty);
}
void main() {
- test({
+ asyncTest(runTests);
+}
+
+Future runTests() async {
+ await test({
'main.dart': """
library main;
@@ -49,9 +54,9 @@
'pkg/lib/foo.dart': """
library lib.foo;
"""},
- warnings: ["The library 'lib.foo' in 'memory:pkg/lib/foo.dart' is loaded"]);
+ warnings: [MessageKind.DUPLICATED_LIBRARY_RESOURCE]);
- test({
+ await test({
'main.dart': """
library main;
@@ -66,9 +71,9 @@
'pkg/lib/bar.dart': """
library lib.bar;
"""},
- warnings: ["The library 'lib.bar' in 'memory:pkg/lib/bar.dart' is loaded"]);
+ warnings: [MessageKind.DUPLICATED_LIBRARY_RESOURCE]);
- test({
+ await test({
'main.dart': """
library main;
@@ -83,9 +88,9 @@
'pkg/lib/baz.dart': """
library lib.baz;
"""},
- warnings: ["The library 'lib.baz' in 'memory:pkg/lib/baz.dart' is loaded"]);
+ warnings: [MessageKind.DUPLICATED_LIBRARY_RESOURCE]);
- test({
+ await test({
'main.dart': """
library main;
@@ -105,9 +110,9 @@
'pkg/lib/boz.dart': """
library lib.boz;
"""},
- warnings: ["The library 'lib.boz' in 'memory:pkg/lib/boz.dart' is loaded"]);
+ warnings: [MessageKind.DUPLICATED_LIBRARY_RESOURCE]);
- test({
+ await test({
'main.dart': """
library main;
@@ -117,9 +122,9 @@
'pkg/lib/qux.dart': """
// No library tag.
"""},
- hints: ["The resource 'memory:pkg/lib/qux.dart' is loaded"]);
+ hints: [MessageKind.DUPLICATED_RESOURCE]);
- test({
+ await test({
'main.dart': """
library main;
@@ -132,7 +137,7 @@
'bar.dart': """
library lib;
"""},
- warnings: ["Duplicated library name 'lib'.",
- "Duplicated library name 'lib'."]);
+ warnings: [MessageKind.DUPLICATED_LIBRARY_NAME,
+ MessageKind.DUPLICATED_LIBRARY_NAME]);
}
diff --git a/tests/compiler/dart2js/expect_annotations2_test.dart b/tests/compiler/dart2js/expect_annotations2_test.dart
index 580ba3a..f0572c5 100644
--- a/tests/compiler/dart2js/expect_annotations2_test.dart
+++ b/tests/compiler/dart2js/expect_annotations2_test.dart
@@ -34,9 +34,11 @@
}'''};
void main() {
- OutputCollector collector = new OutputCollector();
- var compiler = compilerFor(MEMORY_SOURCE_FILES, outputProvider: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ OutputCollector collector = new OutputCollector();
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector);
// Simply check that the constants of the small functions are still in the
// output, and that we don't see the result of constant folding.
String jsOutput = collector.getOutput('', 'js');
@@ -48,5 +50,5 @@
Expect.isFalse(jsOutput.contains('211109'));
Expect.isFalse(jsOutput.contains('82155031'));
Expect.isFalse(jsOutput.contains('4712'));
- }));
+ });
}
diff --git a/tests/compiler/dart2js/expect_annotations_test.dart b/tests/compiler/dart2js/expect_annotations_test.dart
index 8613107..e8ecc40 100644
--- a/tests/compiler/dart2js/expect_annotations_test.dart
+++ b/tests/compiler/dart2js/expect_annotations_test.dart
@@ -2,7 +2,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.
-import 'dart:io';
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/dart2jslib.dart';
@@ -48,8 +47,10 @@
};
main() {
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ Compiler compiler = result.compiler;
Expect.isFalse(compiler.compilationFailed, 'Unsuccessful compilation');
JavaScriptBackend backend = compiler.backend;
Expect.isNotNull(backend.annotations.expectNoInlineClass,
@@ -123,5 +124,5 @@
expectTrustTypeAnnotations: true,
expectedParameterType: coreStringType);
- }));
+ });
}
diff --git a/tests/compiler/dart2js/frontend_checker.dart b/tests/compiler/dart2js/frontend_checker.dart
index 91fb719..67b88d3 100644
--- a/tests/compiler/dart2js/frontend_checker.dart
+++ b/tests/compiler/dart2js/frontend_checker.dart
@@ -40,56 +40,56 @@
Map<String, Set<String>> testOutcomes = {};
String fileName = 'tests/$testFile';
ExtractTestsFromMultitest(new Path(fileName), testSources, testOutcomes);
- return Future.forEach(testSources.keys, (String testName) {
+ return Future.forEach(testSources.keys, (String testName) async {
String testFileName = '$fileName/$testName';
Set<String> expectedOutcome = testOutcomes[testName];
bool expectFailure = testFiles[testFile].contains(testName);
DiagnosticCollector collector = new DiagnosticCollector();
- var compiler = compilerFor(
- {testFileName: testSources[testName]},
- diagnosticHandler: collector,
- options: ['--analyze-only']..addAll(options),
- showDiagnostics: verbose,
- cachedCompiler: cachedCompiler);
- return compiler.run(Uri.parse('memory:$testFileName')).then((_) {
- bool unexpectedResult = false;
- if (expectedOutcome.contains('compile-time error')) {
- if (collector.errors.isEmpty) {
- print('$testFileName: Missing compile-time error.');
- unexpectedResult = true;
- }
- } else if (expectedOutcome.contains('static type warning')) {
- if (collector.warnings.isEmpty) {
- print('$testFileName: Missing static type warning.');
- unexpectedResult = true;
- }
- } else {
- // Expect ok.
- if (!collector.errors.isEmpty ||
- !collector.warnings.isEmpty) {
- collector.errors.forEach((message) {
- print('$testFileName: Unexpected error: ${message.message}');
- });
- collector.warnings.forEach((message) {
- print('$testFileName: Unexpected warning: ${message.message}');
- });
- unexpectedResult = true;
- }
+ CompilationResult result = await runCompiler(
+ entryPoint: Uri.parse('memory:$testFileName'),
+ memorySourceFiles: {testFileName: testSources[testName]},
+ diagnosticHandler: collector,
+ options: ['--analyze-only']..addAll(options),
+ showDiagnostics: verbose,
+ cachedCompiler: cachedCompiler);
+ var compiler = result.compiler;
+ bool unexpectedResult = false;
+ if (expectedOutcome.contains('compile-time error')) {
+ if (collector.errors.isEmpty) {
+ print('$testFileName: Missing compile-time error.');
+ unexpectedResult = true;
}
- if (expectFailure) {
- if (unexpectedResult) {
- unexpectedResult = false;
- } else {
- print('$testFileName: The test is white-listed '
- 'and therefore expected to fail.');
- unexpectedResult = true;
- }
+ } else if (expectedOutcome.contains('static type warning')) {
+ if (collector.warnings.isEmpty) {
+ print('$testFileName: Missing static type warning.');
+ unexpectedResult = true;
}
+ } else {
+ // Expect ok.
+ if (!collector.errors.isEmpty ||
+ !collector.warnings.isEmpty) {
+ collector.errors.forEach((message) {
+ print('$testFileName: Unexpected error: ${message.message}');
+ });
+ collector.warnings.forEach((message) {
+ print('$testFileName: Unexpected warning: ${message.message}');
+ });
+ unexpectedResult = true;
+ }
+ }
+ if (expectFailure) {
if (unexpectedResult) {
- outcomeMismatch = true;
+ unexpectedResult = false;
+ } else {
+ print('$testFileName: The test is white-listed '
+ 'and therefore expected to fail.');
+ unexpectedResult = true;
}
- cachedCompiler = compiler;
- });
+ }
+ if (unexpectedResult) {
+ outcomeMismatch = true;
+ }
+ cachedCompiler = compiler;
});
}).then((_) {
if (outcomeMismatch) {
diff --git a/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart b/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart
index bf9b86e..1f0ab5d 100644
--- a/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart
+++ b/tests/compiler/dart2js/generate_code_with_compile_time_errors_test.dart
@@ -5,7 +5,7 @@
// Test that the compiler can generates code with compile time error according
// to the compiler options.
-library dart2js.test.import;
+library dart2js.test.generate_code_with_compile_time_errors;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
@@ -33,49 +33,46 @@
bool expectHint: false}) async {
DiagnosticCollector collector = new DiagnosticCollector();
OutputCollector outputCollector = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
diagnosticHandler: collector,
outputProvider: outputCollector,
options: options);
+ Compiler compiler = result.compiler;
+ Expect.isFalse(
+ result.isSuccess,
+ "Expected compilation failure.");
+ Expect.isTrue(
+ collector.warnings.isEmpty,
+ "Unexpected warnings: ${collector.warnings}");
+ Expect.isFalse(
+ collector.errors.isEmpty,
+ "Expected compile-time errors.");
+ Expect.equals(
+ expectHint,
+ collector.hints.isNotEmpty,
+ "Unexpected hints: ${collector.warnings}");
- return compiler.run(Uri.parse('memory:main.dart')).then(
- (bool success) {
- Expect.isFalse(
- success,
- "Expected compilation failure.");
- Expect.isTrue(
- collector.warnings.isEmpty,
- "Unexpected warnings: ${collector.warnings}");
- Expect.isFalse(
- collector.errors.isEmpty,
- "Expected compile-time errors.");
- Expect.equals(
- expectHint,
- collector.hints.isNotEmpty,
- "Unexpected hints: ${collector.warnings}");
-
- bool isCodeGenerated;
- if (options.contains('--output-type=dart')) {
- DartBackend backend = compiler.backend;
- isCodeGenerated = backend.outputter.libraryInfo != null;
- } else {
- JavaScriptBackend backend = compiler.backend;
- isCodeGenerated = backend.generatedCode.isNotEmpty;
- }
- Expect.equals(
- expectedCodeGenerated,
- isCodeGenerated,
- expectedCodeGenerated
- ? "Expected generated code for options $options."
- : "Expected no code generated for options $options.");
- Expect.equals(
- expectedOutput,
- outputCollector.outputMap.isNotEmpty,
- expectedOutput
- ? "Expected output for options $options."
- : "Expected no output for options $options.");
- });
+ bool isCodeGenerated;
+ if (options.contains('--output-type=dart')) {
+ DartBackend backend = compiler.backend;
+ isCodeGenerated = backend.outputter.libraryInfo != null;
+ } else {
+ JavaScriptBackend backend = compiler.backend;
+ isCodeGenerated = backend.generatedCode.isNotEmpty;
+ }
+ Expect.equals(
+ expectedCodeGenerated,
+ isCodeGenerated,
+ expectedCodeGenerated
+ ? "Expected generated code for options $options."
+ : "Expected no code generated for options $options.");
+ Expect.equals(
+ expectedOutput,
+ outputCollector.outputMap.isNotEmpty,
+ expectedOutput
+ ? "Expected output for options $options."
+ : "Expected no output for options $options.");
}
void main() {
diff --git a/tests/compiler/dart2js/import_mirrors_test.dart b/tests/compiler/dart2js/import_mirrors_test.dart
index 1b16f76..190d414 100644
--- a/tests/compiler/dart2js/import_mirrors_test.dart
+++ b/tests/compiler/dart2js/import_mirrors_test.dart
@@ -10,7 +10,7 @@
import 'dart:async';
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/dart2jslib.dart' show MessageKind;
+import 'package:compiler/src/warnings.dart' show MessageKind, MessageTemplate;
import 'memory_compiler.dart';
const DIRECT_IMPORT = const {
@@ -342,7 +342,7 @@
Future test(Map sourceFiles,
{expectedPaths,
bool verbose: false,
- bool enableExperimentalMirrors: false}) {
+ bool enableExperimentalMirrors: false}) async {
if (expectedPaths is! List) {
expectedPaths = [expectedPaths];
}
@@ -354,24 +354,26 @@
if (enableExperimentalMirrors) {
options.add('--enable-experimental-mirrors');
}
- var compiler = compilerFor(sourceFiles, diagnosticHandler: collector,
- packageRoot: Uri.parse('memory:/pkg/'),
- options: options);
- return compiler.run(Uri.parse('memory:/main.dart')).then((_) {
- Expect.equals(0, collector.errors.length, 'Errors: ${collector.errors}');
- if (enableExperimentalMirrors) {
- Expect.equals(0, collector.warnings.length,
- 'Warnings: ${collector.errors}');
- } else {
- Expect.equals(1, collector.warnings.length,
- 'Warnings: ${collector.errors}');
- Expect.equals(
- MessageKind.IMPORT_EXPERIMENTAL_MIRRORS.message(
- {'importChain': expectedPaths.join(
- MessageKind.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)}).toString(),
- collector.warnings.first.message);
- }
- });
+ CompilationResult result = await runCompiler(
+ entryPoint: Uri.parse('memory:/main.dart'),
+ memorySourceFiles: sourceFiles,
+ diagnosticHandler: collector,
+ packageRoot: Uri.parse('memory:/pkg/'),
+ options: options);
+ Expect.equals(0, collector.errors.length, 'Errors: ${collector.errors}');
+ if (enableExperimentalMirrors) {
+ Expect.equals(0, collector.warnings.length,
+ 'Warnings: ${collector.errors}');
+ } else {
+ Expect.equals(1, collector.warnings.length,
+ 'Warnings: ${collector.errors}');
+ Expect.equals(
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
+ collector.warnings.first.message.kind);
+ Expect.equals(
+ expectedPaths.join(MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING),
+ collector.warnings.first.message.arguments['importChain']);
+ }
}
Future checkPaths(Map sourceData) {
diff --git a/tests/compiler/dart2js/import_test.dart b/tests/compiler/dart2js/import_test.dart
index aeaa469..ddd4992 100644
--- a/tests/compiler/dart2js/import_test.dart
+++ b/tests/compiler/dart2js/import_test.dart
@@ -8,7 +8,7 @@
library dart2js.test.import;
import 'package:expect/expect.dart';
-import "package:async_helper/async_helper.dart";
+import 'package:async_helper/async_helper.dart';
import 'memory_compiler.dart';
const MEMORY_SOURCE_FILES = const {
@@ -28,25 +28,27 @@
''',
};
-testMissingImports() {
+testMissingImports() async {
var collector = new DiagnosticCollector();
- var compiler = compilerFor(MEMORY_SOURCE_FILES, diagnosticHandler: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
- Expect.equals(4, collector.errors.length);
- Expect.equals(1, collector.warnings.length);
- }));
+ await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ diagnosticHandler: collector);
+ Expect.equals(4, collector.errors.length);
+ Expect.equals(1, collector.warnings.length);
}
-testMissingMain() {
+testMissingMain() async {
var collector = new DiagnosticCollector();
- var compiler = compilerFor({}, diagnosticHandler: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:missing.dart')).then((_) {
- Expect.equals(1, collector.errors.length);
- Expect.equals(0, collector.warnings.length);
- }));
+ await runCompiler(
+ entryPoint: Uri.parse('memory:missing.dart'),
+ diagnosticHandler: collector);
+ Expect.equals(1, collector.errors.length);
+ Expect.equals(0, collector.warnings.length);
}
void main() {
- testMissingImports();
- testMissingMain();
+ asyncTest(() async {
+ await testMissingImports();
+ await testMissingMain();
+ });
}
diff --git a/tests/compiler/dart2js/in_user_code_test.dart b/tests/compiler/dart2js/in_user_code_test.dart
index 6684829..00b2549 100644
--- a/tests/compiler/dart2js/in_user_code_test.dart
+++ b/tests/compiler/dart2js/in_user_code_test.dart
@@ -4,9 +4,10 @@
// Test that the helper [Compiler.inUserCode] works as intended.
+import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
-
+import 'package:compiler/src/dart2jslib.dart' show Compiler;
import 'memory_compiler.dart';
const SOURCE = const {
@@ -42,56 +43,60 @@
""",
};
-void test(List<Uri> entryPoints, Map<String, bool> expectedResults) {
- var compiler = compilerFor(SOURCE,
- options: ['--analyze-only', '--analyze-all'],
- packageRoot: Uri.parse('memory:pkg/'));
- Uri mainUri = null;
- if (entryPoints.length == 1) {
- mainUri = entryPoints[0];
- } else {
- compiler.librariesToAnalyzeWhenRun = entryPoints;
- }
- asyncTest(() => compiler.run(mainUri).then((_) {
- expectedResults.forEach((String uri, bool expectedResult) {
- var element = compiler.libraryLoader.lookupLibrary(Uri.parse(uri));
- Expect.isNotNull(element, "Unknown library '$uri'.");
- Expect.equals(expectedResult, compiler.inUserCode(element),
- expectedResult ? "Library '$uri' expected to be in user code"
- : "Library '$uri' not expected to be in user code");
- });
- }));
+Future test(List<Uri> entryPoints, Map<String, bool> expectedResults) async {
+ CompilationResult result = await runCompiler(
+ entryPoints: entryPoints,
+ memorySourceFiles: SOURCE,
+ options: ['--analyze-only', '--analyze-all'],
+ packageRoot: Uri.parse('memory:pkg/'));
+ Compiler compiler = result.compiler;
+ expectedResults.forEach((String uri, bool expectedResult) {
+ var element = compiler.libraryLoader.lookupLibrary(Uri.parse(uri));
+ Expect.isNotNull(element, "Unknown library '$uri'.");
+ Expect.equals(expectedResult, compiler.inUserCode(element),
+ expectedResult ? "Library '$uri' expected to be in user code"
+ : "Library '$uri' not expected to be in user code");
+ });
}
void main() {
- test([Uri.parse('memory:main.dart')],
- {'memory:main.dart': true,
- 'memory:foo.dart': true,
- 'memory:pkg/sub/bar.dart': true,
- 'memory:pkg/sub/baz.dart': true,
- 'package:sub/bar.dart': false,
- 'package:sub/baz.dart': false,
- 'package:sup/boz.dart': false,
- 'dart:core': false,
- 'dart:async': false});
- test([Uri.parse('dart:async')],
- {'dart:core': true,
- 'dart:async': true});
- test([Uri.parse('package:sub/bar.dart')],
- {'package:sub/bar.dart': true,
- 'package:sub/baz.dart': true,
- 'package:sup/boz.dart': false,
- 'dart:core': false});
- test([Uri.parse('package:sub/bar.dart'), Uri.parse('package:sup/boz.dart')],
- {'package:sub/bar.dart': true,
- 'package:sub/baz.dart': true,
- 'package:sup/boz.dart': true,
- 'dart:core': false});
- test([Uri.parse('dart:async'), Uri.parse('package:sub/bar.dart')],
- {'package:sub/bar.dart': true,
- 'package:sub/baz.dart': true,
- 'package:sup/boz.dart': false,
- 'dart:core': true,
- 'dart:async': true});
+ asyncTest(runTests);
+}
+
+Future runTests() async {
+ await test(
+ [Uri.parse('memory:main.dart')],
+ {'memory:main.dart': true,
+ 'memory:foo.dart': true,
+ 'memory:pkg/sub/bar.dart': true,
+ 'memory:pkg/sub/baz.dart': true,
+ 'package:sub/bar.dart': false,
+ 'package:sub/baz.dart': false,
+ 'package:sup/boz.dart': false,
+ 'dart:core': false,
+ 'dart:async': false});
+ await test(
+ [Uri.parse('dart:async')],
+ {'dart:core': true,
+ 'dart:async': true});
+ await test(
+ [Uri.parse('package:sub/bar.dart')],
+ {'package:sub/bar.dart': true,
+ 'package:sub/baz.dart': true,
+ 'package:sup/boz.dart': false,
+ 'dart:core': false});
+ await test(
+ [Uri.parse('package:sub/bar.dart'), Uri.parse('package:sup/boz.dart')],
+ {'package:sub/bar.dart': true,
+ 'package:sub/baz.dart': true,
+ 'package:sup/boz.dart': true,
+ 'dart:core': false});
+ await test(
+ [Uri.parse('dart:async'), Uri.parse('package:sub/bar.dart')],
+ {'package:sub/bar.dart': true,
+ 'package:sub/baz.dart': true,
+ 'package:sup/boz.dart': false,
+ 'dart:core': true,
+ 'dart:async': true});
}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir.dart b/tests/compiler/dart2js/js_backend_cps_ir.dart
index e3fb44d..f1fd70a 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir.dart
@@ -60,11 +60,15 @@
runTests(List<TestEntry> tests) {
for (TestEntry test in tests) {
Map files = {TEST_MAIN_FILE: test.source};
- asyncTest(() {
- Compiler compiler = compilerFor(files, options: <String>['--use-cps-ir']);
+ asyncTest(() async {
Uri uri = Uri.parse('memory:$TEST_MAIN_FILE');
- return compiler.run(uri).then((bool success) {
- Expect.isTrue(success);
+ try {
+ CompilationResult result = await runCompiler(
+ entryPoint: uri,
+ memorySourceFiles: files,
+ options: <String>['--use-cps-ir']);
+ Expect.isTrue(result.isSuccess);
+ Compiler compiler = result.compiler;
String expectation = test.expectation;
if (expectation != null) {
String expected = test.expectation;
@@ -75,11 +79,11 @@
Expect.fail('Expected:\n$expected\nbut found\n$found');
}
}
- }).catchError((e) {
+ } catch (e) {
print(e);
Expect.fail('The following test failed to compile:\n'
'${formatTest(files)}');
- });
+ }
});
}
}
diff --git a/tests/compiler/dart2js/library_resolution_test.dart b/tests/compiler/dart2js/library_resolution_test.dart
index ed41ebe..5eeb342 100644
--- a/tests/compiler/dart2js/library_resolution_test.dart
+++ b/tests/compiler/dart2js/library_resolution_test.dart
@@ -21,7 +21,8 @@
LibraryElement;
import 'package:compiler/src/dart2jslib.dart' show
- MessageKind;
+ MessageKind,
+ MessageTemplate;
import 'package:compiler/src/null_compiler_output.dart' show
NullCompilerOutput;
@@ -92,7 +93,7 @@
}
String expectedMessage =
- MessageKind.LIBRARY_NOT_FOUND.message(
+ MessageTemplate.TEMPLATES[MessageKind.LIBRARY_NOT_FOUND].message(
{'resolvedUri': 'dart:mock2.dart'}).computeMessage();
int actualMessageCount = 0;
diff --git a/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart b/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart
index 1106be3..992aab0 100644
--- a/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart
+++ b/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart
@@ -3,9 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
-import "package:async_helper/async_helper.dart";
+import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/types/types.dart'
show ContainerTypeMask, TypeMask;
+import 'package:compiler/src/dart2jslib.dart';
import 'memory_compiler.dart';
import 'compiler_helper.dart' show findElement;
@@ -25,8 +26,9 @@
'''};
void main() {
- var compiler = compilerFor(TEST);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result = await runCompiler(memorySourceFiles: TEST);
+ Compiler compiler = result.compiler;
var typesInferrer = compiler.typesTask.typesInferrer;
checkType(String name, type, length) {
@@ -40,5 +42,5 @@
checkType('myList', compiler.typesTask.numType, 42);
checkType('myOtherList', compiler.typesTask.uint31Type, 32);
- }));
+ });
}
diff --git a/tests/compiler/dart2js/malformed_uri_test.dart b/tests/compiler/dart2js/malformed_uri_test.dart
index d51e2dd..70ec4a6 100644
--- a/tests/compiler/dart2js/malformed_uri_test.dart
+++ b/tests/compiler/dart2js/malformed_uri_test.dart
@@ -20,11 +20,13 @@
};
testMalformedUri() {
- var collector = new DiagnosticCollector();
- var compiler = compilerFor(MEMORY_SOURCE_FILES, diagnosticHandler: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var collector = new DiagnosticCollector();
+ await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ diagnosticHandler: collector);
Expect.equals(1, collector.errors.length);
- }));
+ });
}
void main() {
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 44902d8..4d3c893 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -7,13 +7,17 @@
import 'memory_source_file_helper.dart';
-import 'package:compiler/src/null_compiler_output.dart'
- show NullCompilerOutput;
+import 'package:compiler/src/null_compiler_output.dart' show
+ NullCompilerOutput;
+
+import 'package:compiler/src/dart2jslib.dart' show
+ Message;
import 'package:compiler/compiler.dart' show
DiagnosticHandler;
import 'package:compiler/compiler_new.dart' show
+ CompilationResult,
CompilerDiagnostics,
CompilerOutput,
Diagnostic,
@@ -27,53 +31,56 @@
import 'package:compiler/src/library_loader.dart'
show LoadedLibraries;
-import 'package:compiler/src/old_to_new_api.dart';
-
export 'output_collector.dart';
+export 'package:compiler/compiler_new.dart' show
+ CompilationResult;
class DiagnosticMessage {
+ final Message message;
final Uri uri;
final int begin;
final int end;
- final String message;
+ final String text;
final Diagnostic kind;
- DiagnosticMessage(this.uri, this.begin, this.end, this.message, this.kind);
+ DiagnosticMessage(
+ this.message, this.uri, this.begin, this.end, this.text, this.kind);
- String toString() => '$uri:$begin:$end:$message:$kind';
+ String toString() => '$uri:$begin:$end:$text:$kind';
}
class DiagnosticCollector implements CompilerDiagnostics {
List<DiagnosticMessage> messages = <DiagnosticMessage>[];
void call(Uri uri, int begin, int end, String message, Diagnostic kind) {
- report(uri, begin, end, message, kind);
+ report(null, uri, begin, end, message, kind);
}
@override
- void report(Uri uri, int begin, int end, String message, Diagnostic kind) {
- messages.add(new DiagnosticMessage(uri, begin, end, message, kind));
+ void report(Message message,
+ Uri uri, int begin, int end, String text, Diagnostic kind) {
+ messages.add(new DiagnosticMessage(message, uri, begin, end, text, kind));
}
- Iterable<DiagnosticMessage> filterMessagesByKind(Diagnostic kind) {
+ Iterable<DiagnosticMessage> filterMessagesByKinds(List<Diagnostic> kinds) {
return messages.where(
- (DiagnosticMessage message) => message.kind == kind);
+ (DiagnosticMessage message) => kinds.contains(message.kind));
}
Iterable<DiagnosticMessage> get errors {
- return filterMessagesByKind(Diagnostic.ERROR);
+ return filterMessagesByKinds([Diagnostic.ERROR]);
}
Iterable<DiagnosticMessage> get warnings {
- return filterMessagesByKind(Diagnostic.WARNING);
+ return filterMessagesByKinds([Diagnostic.WARNING]);
}
Iterable<DiagnosticMessage> get hints {
- return filterMessagesByKind(Diagnostic.HINT);
+ return filterMessagesByKinds([Diagnostic.HINT]);
}
Iterable<DiagnosticMessage> get infos {
- return filterMessagesByKind(Diagnostic.INFO);
+ return filterMessagesByKinds([Diagnostic.INFO]);
}
/// `true` if non-verbose messages has been collected.
@@ -88,9 +95,10 @@
const MultiDiagnostics([this.diagnosticsList = const []]);
@override
- void report(Uri uri, int begin, int end, String message, Diagnostic kind) {
+ void report(Message message, Uri uri, int begin, int end,
+ String text, Diagnostic kind) {
for (CompilerDiagnostics diagnostics in diagnosticsList) {
- diagnostics.report(uri, begin, end, message, kind);
+ diagnostics.report(message, uri, begin, end, text, kind);
}
}
}
@@ -116,11 +124,45 @@
Expando<MemorySourceFileProvider> expando =
new Expando<MemorySourceFileProvider>();
+Future<CompilationResult> runCompiler(
+ {Map<String, String> memorySourceFiles: const <String, String>{},
+ Uri entryPoint,
+ List<Uri> entryPoints,
+ CompilerDiagnostics diagnosticHandler,
+ CompilerOutput outputProvider,
+ List<String> options: const <String>[],
+ Compiler cachedCompiler,
+ bool showDiagnostics: true,
+ Uri packageRoot,
+ Uri packageConfig,
+ PackagesDiscoveryProvider packagesDiscoveryProvider,
+ void beforeRun(Compiler compiler)}) async {
+ if (entryPoint == null) {
+ entryPoint = Uri.parse('memory:main.dart');
+ }
+ Compiler compiler = compilerFor(
+ memorySourceFiles,
+ diagnosticHandler: diagnosticHandler,
+ outputProvider: outputProvider,
+ options: options,
+ cachedCompiler: cachedCompiler,
+ showDiagnostics: showDiagnostics,
+ packageRoot: packageRoot,
+ packageConfig: packageConfig,
+ packagesDiscoveryProvider: packagesDiscoveryProvider);
+ compiler.librariesToAnalyzeWhenRun = entryPoints;
+ if (beforeRun != null) {
+ beforeRun(compiler);
+ }
+ bool isSuccess = await compiler.run(entryPoint);
+ return new CompilationResult(compiler, isSuccess: isSuccess);
+}
+
Compiler compilerFor(
Map<String, String> memorySourceFiles,
{CompilerDiagnostics diagnosticHandler,
CompilerOutput outputProvider,
- List<String> options: const [],
+ List<String> options: const <String>[],
Compiler cachedCompiler,
bool showDiagnostics: true,
Uri packageRoot,
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index 244d5a0..b579e95 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -9,7 +9,8 @@
import 'package:compiler/src/dart2jslib.dart' show
Compiler,
- MessageKind;
+ MessageKind,
+ MessageTemplate;
import 'package:compiler/src/dart_backend/dart_backend.dart' show
DartBackend;
import 'package:compiler/src/old_to_new_api.dart' show
@@ -52,11 +53,11 @@
// If you add something here, please file a *new* bug report.
]);
-Future<Compiler> check(MessageKind kind, Compiler cachedCompiler) {
- Expect.isNotNull(kind.howToFix);
- Expect.isFalse(kind.examples.isEmpty);
+Future<Compiler> check(MessageTemplate template, Compiler cachedCompiler) {
+ Expect.isNotNull(template.howToFix);
+ Expect.isFalse(template.examples.isEmpty);
- return Future.forEach(kind.examples, (example) {
+ return Future.forEach(template.examples, (example) {
if (example is String) {
example = {'main.dart': example};
} else {
@@ -77,13 +78,13 @@
if (cachedCompiler != null) {
oldBackendIsDart = cachedCompiler.backend is DartBackend;
}
- bool newBackendIsDart = kind.options.contains('--output-type=dart');
+ bool newBackendIsDart = template.options.contains('--output-type=dart');
Compiler compiler = compilerFor(
example,
diagnosticHandler: new LegacyCompilerDiagnostics(collect),
options: ['--analyze-only',
- '--enable-experimental-mirrors']..addAll(kind.options),
+ '--enable-experimental-mirrors']..addAll(template.options),
cachedCompiler:
// TODO(johnniwinther): Remove this restriction when constant
// values can be computed directly from the expressions.
@@ -93,8 +94,8 @@
Expect.isFalse(messages.isEmpty, 'No messages in """$example"""');
- String expectedText = !kind.hasHowToFix
- ? kind.template : '${kind.template}\n${kind.howToFix}';
+ String expectedText = !template.hasHowToFix
+ ? template.template : '${template.template}\n${template.howToFix}';
String pattern = expectedText.replaceAllMapped(
new RegExp(ESCAPE_REGEXP), (m) => '\\${m[0]}');
pattern = pattern.replaceAll(new RegExp(r'#\\\{[^}]*\\\}'), '.*');
@@ -116,7 +117,7 @@
for (String message in unexpectedMessages) {
print("Unexpected message: $message");
}
- if (!kindsWithExtraMessages.contains(kind)) {
+ if (!kindsWithExtraMessages.contains(template.kind)) {
// Try changing the error reporting logic before adding an exception
// to [kindsWithExtraMessages].
throw 'Unexpected messages found.';
@@ -136,7 +137,8 @@
e, MessageKind.GENERIC,
{'text': 'Pending class to be resolved.'});
}
- Expect.isTrue(!pendingStuff || kindsWithPendingClasses.contains(kind));
+ Expect.isTrue(!pendingStuff ||
+ kindsWithPendingClasses.contains(template));
if (!pendingStuff) {
// If there is pending stuff, or the compiler was cancelled, we
diff --git a/tests/compiler/dart2js/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index 368d51b..9796595 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -5,58 +5,42 @@
import 'package:expect/expect.dart';
import 'dart:async';
import "package:async_helper/async_helper.dart";
-import 'package:compiler/src/dart2jslib.dart' show
- DualKind,
- MessageKind;
+import 'package:compiler/src/warnings.dart' show
+ MessageKind,
+ MessageTemplate;
import 'message_kind_helper.dart';
-import 'dart:mirrors';
-
main(List<String> arguments) {
- ClassMirror cls = reflectClass(MessageKind);
- Map<String, MessageKind> kinds = <String, MessageKind>{};
- cls.declarations.forEach((Symbol name, DeclarationMirror declaration) {
- if (declaration is! VariableMirror) return;
- VariableMirror variable = declaration;
- if (variable.isStatic) {
- var value = cls.getField(name).reflectee;
- String variableName = MirrorSystem.getName(name);
- if (variableName == 'IMPORT_EXPERIMENTAL_MIRRORS_PADDING') {
- return;
- }
- if (value is MessageKind) {
- kinds[variableName] = value;
- } else {
- Expect.fail("Weird static field: '${variableName}'.");
- }
- }
- });
- List<String> names = kinds.keys.toList()..sort();
- List<String> examples = <String>[];
- for (String name in names) {
+ List<MessageTemplate> examples = <MessageTemplate>[];
+ for (MessageKind kind in MessageKind.values) {
+ MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+ Expect.isNotNull(template, "No template for $kind.");
+ Expect.equals(kind, template.kind,
+ "Invalid MessageTemplate.kind for $kind, found ${template.kind}.");
+
+ String name = '${kind.toString()}'.substring('MessageKind.'.length);
if (!arguments.isEmpty && !arguments.contains(name)) continue;
- MessageKind kind = kinds[name];
if (name == 'GENERIC' // Shouldn't be used.
// We can't provoke a crash.
|| name == 'COMPILER_CRASHED'
|| name == 'PLEASE_REPORT_THE_CRASH'
// We cannot provide examples for patch errors.
|| name.startsWith('PATCH_')) continue;
- if (kind.examples != null) {
- examples.add(name);
+ if (template.examples != null) {
+ examples.add(template);
} else {
print("No example in '$name'");
}
};
var cachedCompiler;
- asyncTest(() => Future.forEach(examples, (String name) {
- print("Checking '$name'.");
+ asyncTest(() => Future.forEach(examples, (MessageTemplate template) {
+ print("Checking '${template.kind}'.");
Stopwatch sw = new Stopwatch()..start();
- return check(kinds[name], cachedCompiler).then((var compiler) {
+ return check(template, cachedCompiler).then((var compiler) {
cachedCompiler = compiler;
sw.stop();
- print("Checked '$name' in ${sw.elapsedMilliseconds}ms.");
+ print("Checked '${template.kind}' in ${sw.elapsedMilliseconds}ms.");
});
}));
}
diff --git a/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart b/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart
index 093833e..20411b7 100644
--- a/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart
+++ b/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart
@@ -6,7 +6,7 @@
import 'package:expect/expect.dart';
import "package:async_helper/async_helper.dart";
-import 'memory_compiler.dart' show compilerFor;
+import 'memory_compiler.dart' show runCompiler;
import 'compiler_helper.dart' show findElement;
import 'type_mask_test_helper.dart';
@@ -24,13 +24,14 @@
};
void main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ var compiler = result.compiler;
var element = findElement(compiler, 'field');
var typesTask = compiler.typesTask;
var typesInferrer = typesTask.typesInferrer;
Expect.equals(typesTask.uint31Type,
simplify(typesInferrer.getTypeOfElement(element), compiler),
'field');
- }));
+ });
}
diff --git a/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart b/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart
index 8395fed..54252ec 100644
--- a/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart
+++ b/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart
@@ -6,7 +6,7 @@
import 'package:expect/expect.dart';
import "package:async_helper/async_helper.dart";
-import 'memory_compiler.dart' show compilerFor;
+import 'memory_compiler.dart' show runCompiler;
import 'compiler_helper.dart' show findElement;
import 'type_mask_test_helper.dart';
@@ -24,13 +24,14 @@
};
void main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ var compiler = result.compiler;
var element = findElement(compiler, 'field');
var typesTask = compiler.typesTask;
var typesInferrer = typesTask.typesInferrer;
Expect.equals(typesTask.uint31Type,
simplify(typesInferrer.getTypeOfElement(element), compiler),
'field');
- }));
+ });
}
diff --git a/tests/compiler/dart2js/mirror_helper_rename_test.dart b/tests/compiler/dart2js/mirror_helper_rename_test.dart
index 2428dfe..76d3adb 100644
--- a/tests/compiler/dart2js/mirror_helper_rename_test.dart
+++ b/tests/compiler/dart2js/mirror_helper_rename_test.dart
@@ -5,7 +5,7 @@
import "package:expect/expect.dart";
import 'dart:async';
import "package:async_helper/async_helper.dart";
-import 'memory_compiler.dart' show compilerFor, OutputCollector;
+import 'memory_compiler.dart' show runCompiler, OutputCollector;
import 'package:compiler/src/apiimpl.dart' show
Compiler;
import 'package:compiler/src/tree/tree.dart' show
@@ -14,80 +14,81 @@
import 'package:compiler/src/mirror_renamer/mirror_renamer.dart';
main() {
- testWithMirrorHelperLibrary(minify: true);
- testWithMirrorHelperLibrary(minify: false);
- testWithoutMirrorHelperLibrary(minify: true);
- testWithoutMirrorHelperLibrary(minify: false);
+ asyncTest(() async {
+ await testWithMirrorHelperLibrary(minify: true);
+ await testWithMirrorHelperLibrary(minify: false);
+ await testWithoutMirrorHelperLibrary(minify: true);
+ await testWithoutMirrorHelperLibrary(minify: false);
+ });
}
-Future<Compiler> runCompiler({OutputCollector outputCollector,
- bool useMirrorHelperLibrary: false,
- bool minify: false}) {
+Future<Compiler> run({OutputCollector outputCollector,
+ bool useMirrorHelperLibrary: false,
+ bool minify: false}) async {
List<String> options = ['--output-type=dart'];
if (minify) {
options.add('--minify');
}
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES, outputProvider: outputCollector, options: options);
- DartBackend backend = compiler.backend;
- backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
- return
- compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) => compiler);
+ var result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: outputCollector,
+ options: options,
+ beforeRun: (Compiler compiler) {
+ DartBackend backend = compiler.backend;
+ backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
+ });
+ return result.compiler;
}
-void testWithMirrorHelperLibrary({bool minify}) {
+Future testWithMirrorHelperLibrary({bool minify}) async {
OutputCollector outputCollector = new OutputCollector();
- asyncTest(() =>
- runCompiler(outputCollector: outputCollector,
- useMirrorHelperLibrary: true,
- minify: minify)
- .then((Compiler compiler) {
- DartBackend backend = compiler.backend;
- MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
- Map<Node, String> renames = backend.placeholderRenamer.renames;
- Map<String, String> symbols = mirrorRenamer.symbols;
+ Compiler compiler = await run(
+ outputCollector: outputCollector,
+ useMirrorHelperLibrary: true,
+ minify: minify);
+ DartBackend backend = compiler.backend;
+ MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
+ Map<Node, String> renames = backend.placeholderRenamer.renames;
+ Map<String, String> symbols = mirrorRenamer.symbols;
- Expect.isFalse(null == mirrorRenamer.helperLibrary);
- Expect.isFalse(null == mirrorRenamer.getNameFunction);
+ Expect.isFalse(null == mirrorRenamer.helperLibrary);
+ Expect.isFalse(null == mirrorRenamer.getNameFunction);
- for (Node n in renames.keys) {
- if (symbols.containsKey(renames[n])) {
- if(n.toString() == 'getName') {
- Expect.equals(
- MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION,
- symbols[renames[n]]);
- } else {
- Expect.equals(n.toString(), symbols[renames[n]]);
- }
+ for (Node n in renames.keys) {
+ if (symbols.containsKey(renames[n])) {
+ if(n.toString() == 'getName') {
+ Expect.equals(
+ MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION,
+ symbols[renames[n]]);
+ } else {
+ Expect.equals(n.toString(), symbols[renames[n]]);
}
}
+ }
- String output = outputCollector.getOutput('', 'dart');
- String getNameMatch = MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION;
- Iterable i = getNameMatch.allMatches(output);
- print(output);
- if (minify) {
- Expect.equals(0, i.length);
- } else {
- // Appears twice in code (defined & called).
- Expect.equals(2, i.length);
- }
+ String output = outputCollector.getOutput('', 'dart');
+ String getNameMatch = MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION;
+ Iterable i = getNameMatch.allMatches(output);
+ print(output);
+ if (minify) {
+ Expect.equals(0, i.length);
+ } else {
+ // Appears twice in code (defined & called).
+ Expect.equals(2, i.length);
+ }
- RegExp mapMatch = new RegExp('const<String,( )?String>');
- i = mapMatch.allMatches(output);
- Expect.equals(1, i.length);
- }));
+ RegExp mapMatch = new RegExp('const<String,( )?String>');
+ i = mapMatch.allMatches(output);
+ Expect.equals(1, i.length);
}
-void testWithoutMirrorHelperLibrary({bool minify}) {
- asyncTest(() => runCompiler(useMirrorHelperLibrary: false, minify: minify).
- then((Compiler compiler) {
- DartBackend backend = compiler.backend;
- MirrorRenamer mirrorRenamer = backend.mirrorRenamer;
+Future testWithoutMirrorHelperLibrary({bool minify}) async {
+ Compiler compiler = await run(useMirrorHelperLibrary: false, minify: minify);
+ DartBackend backend = compiler.backend;
+ MirrorRenamer mirrorRenamer = backend.mirrorRenamer;
- Expect.equals(null, mirrorRenamer.helperLibrary);
- Expect.equals(null, mirrorRenamer.getNameFunction);
- }));
+ Expect.equals(null, mirrorRenamer.helperLibrary);
+ Expect.equals(null, mirrorRenamer.getNameFunction);
}
const MEMORY_SOURCE_FILES = const <String, String> {
diff --git a/tests/compiler/dart2js/mirror_helper_test.dart b/tests/compiler/dart2js/mirror_helper_test.dart
index e454c7e..e823b8b 100644
--- a/tests/compiler/dart2js/mirror_helper_test.dart
+++ b/tests/compiler/dart2js/mirror_helper_test.dart
@@ -5,7 +5,7 @@
import "package:expect/expect.dart";
import 'dart:async';
import "package:async_helper/async_helper.dart";
-import 'memory_compiler.dart' show compilerFor;
+import 'memory_compiler.dart' show runCompiler;
import 'package:compiler/src/apiimpl.dart' show
Compiler;
import 'package:compiler/src/elements/elements.dart' show
@@ -18,63 +18,62 @@
MirrorRenamerImpl;
main() {
- testWithMirrorRenaming(minify: true);
- testWithMirrorRenaming(minify: false);
- testWithoutMirrorRenaming(minify: true);
- testWithoutMirrorRenaming(minify: false);
+ asyncTest(() async {
+ await testWithMirrorRenaming(minify: true);
+ await testWithMirrorRenaming(minify: false);
+ await testWithoutMirrorRenaming(minify: true);
+ await testWithoutMirrorRenaming(minify: false);
+ });
}
-Future<Compiler> runCompiler({useMirrorHelperLibrary: false, minify: false}) {
+Future<Compiler> run({useMirrorHelperLibrary: false, minify: false}) async {
List<String> options = ['--output-type=dart'];
if (minify) {
options.add('--minify');
}
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES, options: options);
+ var result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ options: options,
+ beforeRun: (Compiler compiler) {
+ DartBackend backend = compiler.backend;
+ backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
+ });
+ return result.compiler;
+}
+
+Future testWithMirrorRenaming({bool minify}) async {
+ Compiler compiler = await run(useMirrorHelperLibrary: true, minify: minify);
DartBackend backend = compiler.backend;
- backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
- return
- compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) => compiler);
+ MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
+ Map<Node, String> renames = backend.placeholderRenamer.renames;
+ Iterable<LibraryElement> imports =
+ backend.placeholderRenamer.platformImports.keys;
+
+ FunctionExpression node = backend.memberNodes.values.first.first;
+ Block block = node.body;
+ ExpressionStatement getNameFunctionNode = block.statements.nodes.head;
+ Send send = getNameFunctionNode.expression;
+
+ Expect.equals(renames[mirrorRenamer.getNameFunctionNode.name],
+ renames[send.selector]);
+ Expect.equals("",
+ renames[send.receiver]);
+ Expect.equals(1, imports.length);
}
-void testWithMirrorRenaming({bool minify}) {
- asyncTest(() => runCompiler(useMirrorHelperLibrary: true, minify: minify).
- then((Compiler compiler) {
+Future testWithoutMirrorRenaming({bool minify}) async {
+ Compiler compiler = await run(useMirrorHelperLibrary: false, minify: minify);
+ DartBackend backend = compiler.backend;
+ Map<Node, String> renames = backend.placeholderRenamer.renames;
+ Iterable<LibraryElement> imports =
+ backend.placeholderRenamer.platformImports.keys;
+ FunctionExpression node = backend.memberNodes.values.first.first;
+ Block block = node.body;
+ ExpressionStatement getNameFunctionNode = block.statements.nodes.head;
+ Send send = getNameFunctionNode.expression;
- DartBackend backend = compiler.backend;
- MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
- Map<Node, String> renames = backend.placeholderRenamer.renames;
- Iterable<LibraryElement> imports =
- backend.placeholderRenamer.platformImports.keys;
-
- FunctionExpression node = backend.memberNodes.values.first.first;
- Block block = node.body;
- ExpressionStatement getNameFunctionNode = block.statements.nodes.head;
- Send send = getNameFunctionNode.expression;
-
- Expect.equals(renames[mirrorRenamer.getNameFunctionNode.name],
- renames[send.selector]);
- Expect.equals("",
- renames[send.receiver]);
- Expect.equals(1, imports.length);
- }));
-}
-
-void testWithoutMirrorRenaming({bool minify}) {
- asyncTest(() => runCompiler(useMirrorHelperLibrary: false, minify: minify).
- then((Compiler compiler) {
-
- DartBackend backend = compiler.backend;
- Map<Node, String> renames = backend.placeholderRenamer.renames;
- Iterable<LibraryElement> imports =
- backend.placeholderRenamer.platformImports.keys;
- FunctionExpression node = backend.memberNodes.values.first.first;
- Block block = node.body;
- ExpressionStatement getNameFunctionNode = block.statements.nodes.head;
- Send send = getNameFunctionNode.expression;
-
- Expect.isFalse(renames.containsKey(send.selector));
- Expect.equals(1, imports.length);
- }));
+ Expect.isFalse(renames.containsKey(send.selector));
+ Expect.equals(1, imports.length);
}
const MEMORY_SOURCE_FILES = const <String, String> {
diff --git a/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart b/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart
index defbf6c..47c8145 100644
--- a/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart
+++ b/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart
@@ -5,7 +5,7 @@
import "package:expect/expect.dart";
import 'dart:async';
import "package:async_helper/async_helper.dart";
-import 'memory_compiler.dart' show compilerFor;
+import 'memory_compiler.dart' show runCompiler;
import 'package:compiler/src/apiimpl.dart' show
Compiler;
import 'package:compiler/src/dart_backend/dart_backend.dart' show
@@ -16,59 +16,60 @@
MirrorRenamerImpl;
main() {
- testUniqueMinification();
- testNoUniqueMinification();
+ asyncTest(() async {
+ await testUniqueMinification();
+ await testNoUniqueMinification();
+ });
}
-Future<Compiler> runCompiler({useMirrorHelperLibrary: false, minify: false}) {
+Future<Compiler> run({useMirrorHelperLibrary: false, minify: false}) async {
List<String> options = ['--output-type=dart'];
if (minify) {
options.add('--minify');
}
- Compiler compiler = compilerFor(MEMORY_SOURCE_FILES, options: options);
- DartBackend backend = compiler.backend;
- backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
- return
- compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) => compiler);
+ var result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ options: options,
+ beforeRun: (Compiler compiler) {
+ DartBackend backend = compiler.backend;
+ backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
+ });
+ return result.compiler;
}
-void testUniqueMinification() {
- asyncTest(() => runCompiler(useMirrorHelperLibrary: true, minify: true).
- then((Compiler compiler) {
- DartBackend backend = compiler.backend;
- MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
- Map<Node, String> renames = backend.placeholderRenamer.renames;
- Map<String, String> symbols = mirrorRenamer.symbols;
+Future testUniqueMinification() async {
+ Compiler compiler = await run(useMirrorHelperLibrary: true, minify: true);
+ DartBackend backend = compiler.backend;
+ MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
+ Map<Node, String> renames = backend.placeholderRenamer.renames;
+ Map<String, String> symbols = mirrorRenamer.symbols;
- // Check that no two different source code names get the same mangled name,
- // with the exception of MirrorSystem.getName that gets renamed to the same
- // mangled name as the getNameHelper from _mirror_helper.dart.
- for (Node node in renames.keys) {
- Identifier identifier = node.asIdentifier();
- if (identifier != null) {
- String source = identifier.source;
- Send send = mirrorRenamer.mirrorSystemGetNameNodes.first;
- if (send.selector == node)
- continue;
- if (symbols.containsKey(renames[node])) {
- print(node);
- Expect.equals(source, symbols[renames[node]]);
- }
+ // Check that no two different source code names get the same mangled name,
+ // with the exception of MirrorSystem.getName that gets renamed to the same
+ // mangled name as the getNameHelper from _mirror_helper.dart.
+ for (Node node in renames.keys) {
+ Identifier identifier = node.asIdentifier();
+ if (identifier != null) {
+ String source = identifier.source;
+ Send send = mirrorRenamer.mirrorSystemGetNameNodes.first;
+ if (send.selector == node)
+ continue;
+ if (symbols.containsKey(renames[node])) {
+ print(node);
+ Expect.equals(source, symbols[renames[node]]);
}
}
- }));
+ }
}
-void testNoUniqueMinification() {
- asyncTest(() => runCompiler(useMirrorHelperLibrary: false, minify: true).
- then((Compiler compiler) {
- DartBackend backend = compiler.backend;
- Map<Node, String> renames = backend.placeholderRenamer.renames;
+Future testNoUniqueMinification() async {
+ Compiler compiler = await run(useMirrorHelperLibrary: false, minify: true);
+ DartBackend backend = compiler.backend;
+ Map<Node, String> renames = backend.placeholderRenamer.renames;
- // 'Foo' appears twice and 'invocation' and 'hest' get the same mangled
- // name.
- Expect.equals(renames.values.toSet().length, renames.values.length - 2);
- }));
+ // 'Foo' appears twice and 'invocation' and 'hest' get the same mangled
+ // name.
+ Expect.equals(renames.values.toSet().length, renames.values.length - 2);
}
const MEMORY_SOURCE_FILES = const <String, String> {
diff --git a/tests/compiler/dart2js/mirror_private_name_inheritance_test.dart b/tests/compiler/dart2js/mirror_private_name_inheritance_test.dart
index 6277637..8626b55 100644
--- a/tests/compiler/dart2js/mirror_private_name_inheritance_test.dart
+++ b/tests/compiler/dart2js/mirror_private_name_inheritance_test.dart
@@ -6,7 +6,7 @@
import 'package:expect/expect.dart';
import "package:async_helper/async_helper.dart";
-import 'memory_compiler.dart' show compilerFor;
+import 'memory_compiler.dart' show runCompiler;
import 'compiler_helper.dart' show findElement;
const MEMORY_SOURCE_FILES = const <String, String> {
@@ -36,8 +36,9 @@
};
void main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ var compiler = result.compiler;
var superclass = findElement(compiler, 'Super', Uri.parse('memory:lib.dart'));
var subclass = findElement(compiler, 'Subclass');
@@ -45,5 +46,5 @@
print(superclass.lookupMember('_private'));
Expect.isTrue(oracle(superclass.lookupMember('_private')));
Expect.isFalse(oracle(subclass.lookupMember('_private')));
- }));
+ });
}
diff --git a/tests/compiler/dart2js/mirror_tree_shaking_test.dart b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
index 4548a70..87accd5 100644
--- a/tests/compiler/dart2js/mirror_tree_shaking_test.dart
+++ b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
@@ -13,9 +13,10 @@
main() {
DiagnosticCollector collector = new DiagnosticCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES, diagnosticHandler: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES, diagnosticHandler: collector);
+ Compiler compiler = result.compiler;
Expect.isTrue(collector.errors.isEmpty);
Expect.isTrue(collector.infos.isEmpty);
Expect.isFalse(compiler.compilationFailed);
@@ -27,7 +28,7 @@
Expect.isFalse(compiler.disableTypeInference);
JavaScriptBackend backend = compiler.backend;
Expect.isFalse(backend.hasRetainedMetadata);
- }));
+ });
}
const Map MEMORY_SOURCE_FILES = const {
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 2a525c9..c68281f 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -10,7 +10,7 @@
import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart' show
- compilerFor;
+ runCompiler;
import 'package:compiler/src/apiimpl.dart' show
Compiler;
@@ -50,11 +50,12 @@
}
void main() {
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ asyncTest(() async {
+ var result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
diagnosticHandler: new LegacyCompilerDiagnostics(expectOnlyVerboseInfo),
options: ['--enable-experimental-mirrors']);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ Compiler compiler = result.compiler;
print('');
List generatedCode =
Elements.sortedByPosition(compiler.enqueuer.codegen.generatedCode.keys);
@@ -147,7 +148,7 @@
Expect.equals(
1, fooConstantCount,
"The type literal 'Foo' is duplicated or missing.");
- }));
+ });
}
const MEMORY_SOURCE_FILES = const <String, String> {
diff --git a/tests/compiler/dart2js/missing_file_test.dart b/tests/compiler/dart2js/missing_file_test.dart
index 7d88eb8..26a4e9b 100644
--- a/tests/compiler/dart2js/missing_file_test.dart
+++ b/tests/compiler/dart2js/missing_file_test.dart
@@ -21,34 +21,28 @@
''',
};
-Future runCompiler(Uri main, String expectedMessage) {
+Future runTest(Uri main, MessageKind expectedMessageKind) async {
print("\n\n\n");
DiagnosticCollector diagnostics = new DiagnosticCollector();
OutputCollector output = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
diagnosticHandler: diagnostics,
outputProvider: output);
- return compiler.run(main).then((_) {
- Expect.isFalse(output.hasExtraOutput);
- Expect.equals(1, diagnostics.errors.length);
- Expect.equals(expectedMessage, diagnostics.errors.first.message);
- });
+ Expect.isFalse(output.hasExtraOutput);
+ Expect.equals(1, diagnostics.errors.length);
+ Expect.equals(expectedMessageKind, diagnostics.errors.first.message.kind);
}
void main() {
- asyncTest(() => Future.forEach([
- () => runCompiler(
- Uri.parse('memory:main.dart'),
- "Can't read 'memory:foo.dart' "
- "(Exception: No such file memory:foo.dart)."),
- () => runCompiler(
- Uri.parse('memory:foo.dart'),
- "Exception: No such file memory:foo.dart"),
- () => runCompiler(
- Uri.parse('dart:foo'),
- "Library not found 'dart:foo'."),
- ], (f) => f()));
+ asyncTest(() async {
+ await runTest(
+ Uri.parse('memory:main.dart'), MessageKind.READ_SCRIPT_ERROR);
+ await runTest(
+ Uri.parse('memory:foo.dart'), MessageKind.READ_SCRIPT_ERROR);
+ await runTest(
+ Uri.parse('dart:foo'), MessageKind.READ_SCRIPT_ERROR);
+ });
}
diff --git a/tests/compiler/dart2js/mixin_constructor_default_parameter_values_test.dart b/tests/compiler/dart2js/mixin_constructor_default_parameter_values_test.dart
index 705eece..9d0fc86 100644
--- a/tests/compiler/dart2js/mixin_constructor_default_parameter_values_test.dart
+++ b/tests/compiler/dart2js/mixin_constructor_default_parameter_values_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// Ensure that the inferrer looks at default values for parameters in
-// synthetic constructors using the correct context. If the constructor call
+// synthetic constructors using the correct context. If the constructor call
// to D without optional parameters is inferred using D's context, the default
// value `_SECRET` will not be visible and compilation will fail.
@@ -42,7 +42,6 @@
};
main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')));
+ asyncTest(() => runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES));
}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 3284514..6f8cb51 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -166,8 +166,9 @@
// warnings.
void reportWarning(Spannable node, MessageKind messageKind,
[Map arguments = const {}]) {
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
reportDiagnostic(node,
- messageKind.message(arguments, terseDiagnostics),
+ template.message(arguments, terseDiagnostics),
api.Diagnostic.WARNING);
}
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index a9f96ef..c823f6b 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -196,6 +196,7 @@
'patch': 'const patch = const _Patch(null);',
'patch_full': 'const patch_full = const _Patch("full");',
'patch_lazy': 'const patch_lazy = const _Patch("lazy");',
+ 'patch_startup': 'const patch_startup = const _Patch("startup");',
'propertyTypeCast': 'propertyTypeCast(x) {}',
'propertyTypeCheck': 'propertyTypeCheck(value, property) {}',
'requiresPreamble': 'requiresPreamble() {}',
diff --git a/tests/compiler/dart2js/number_output_test.dart b/tests/compiler/dart2js/number_output_test.dart
index 6ced21c..6f873a5 100644
--- a/tests/compiler/dart2js/number_output_test.dart
+++ b/tests/compiler/dart2js/number_output_test.dart
@@ -2,8 +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:expect/expect.dart";
-import "package:async_helper/async_helper.dart";
+import 'dart:async';
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
import 'memory_compiler.dart';
const MEMORY_SOURCE_FILES = const {
@@ -15,35 +16,37 @@
print(-22230000);
}'''};
-void test({bool minify}) {
+Future test({bool minify}) async {
OutputCollector collector = new OutputCollector();
- var compiler = compilerFor(MEMORY_SOURCE_FILES,
- outputProvider: collector,
- options: minify ? ['--minify'] : []);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
- // Check that we use the shorter exponential representations.
- String jsOutput = collector.getOutput('', 'js');
- print(jsOutput);
+ await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector,
+ options: minify ? ['--minify'] : []);
- if (minify) {
- Expect.isTrue(jsOutput.contains('123e5')); // Shorter than 12300000.
- Expect.isFalse(jsOutput.contains('12300000'));
- Expect.isTrue(jsOutput.contains('-2223e4')); // Shorter than -22230000.
- Expect.isFalse(jsOutput.contains('-22230000'));
- } else {
- Expect.isTrue(jsOutput.contains('12300000'));
- Expect.isTrue(jsOutput.contains('-22230000'));
- }
- Expect.isTrue(jsOutput.contains('12345678901234568e8'));
- Expect.isTrue(jsOutput.contains('17976931348623157e292'));
- Expect.isFalse(jsOutput.contains('1234567890123456789012345'));
- // The decimal expansion of double.MAX_FINITE has 308 digits. We only check
- // for its prefix.
- Expect.isFalse(jsOutput.contains('179769313486231570814527423731'));
- }));
+ // Check that we use the shorter exponential representations.
+ String jsOutput = collector.getOutput('', 'js');
+ print(jsOutput);
+
+ if (minify) {
+ Expect.isTrue(jsOutput.contains('123e5')); // Shorter than 12300000.
+ Expect.isFalse(jsOutput.contains('12300000'));
+ Expect.isTrue(jsOutput.contains('-2223e4')); // Shorter than -22230000.
+ Expect.isFalse(jsOutput.contains('-22230000'));
+ } else {
+ Expect.isTrue(jsOutput.contains('12300000'));
+ Expect.isTrue(jsOutput.contains('-22230000'));
+ }
+ Expect.isTrue(jsOutput.contains('12345678901234568e8'));
+ Expect.isTrue(jsOutput.contains('17976931348623157e292'));
+ Expect.isFalse(jsOutput.contains('1234567890123456789012345'));
+ // The decimal expansion of double.MAX_FINITE has 308 digits. We only check
+ // for its prefix.
+ Expect.isFalse(jsOutput.contains('179769313486231570814527423731'));
}
main() {
- test(minify: true);
- test(minify: false);
+ asyncTest(() async {
+ await test(minify: true);
+ await test(minify: false);
+ });
}
diff --git a/tests/compiler/dart2js/package_root_test.dart b/tests/compiler/dart2js/package_root_test.dart
index f1e6ee6..122170c 100644
--- a/tests/compiler/dart2js/package_root_test.dart
+++ b/tests/compiler/dart2js/package_root_test.dart
@@ -12,6 +12,8 @@
import 'package:expect/expect.dart';
import 'package:compiler/compiler.dart'
show DiagnosticHandler, Diagnostic, PackagesDiscoveryProvider;
+import 'package:compiler/src/dart2jslib.dart'
+ show MessageKind;
import 'package:package_config/packages.dart';
import 'memory_compiler.dart';
@@ -30,60 +32,58 @@
final Uri PACKAGE_CONFIG_URI = Uri.parse('memory:package.config');
-void runCompiler(Uri main,
- bool checkError(DiagnosticMessage message),
- {Uri packageRoot,
- Uri packageConfig,
- PackagesDiscoveryProvider packagesDiscoveryProvider}) {
+Future runTest(Uri main,
+ MessageKind expectedMessageKind,
+ {Uri packageRoot,
+ Uri packageConfig,
+ PackagesDiscoveryProvider packagesDiscoveryProvider}) async {
DiagnosticCollector collector = new DiagnosticCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
+ await runCompiler(
+ entryPoint: main,
+ memorySourceFiles: MEMORY_SOURCE_FILES,
diagnosticHandler: collector,
packageRoot: packageRoot,
packageConfig: packageConfig,
packagesDiscoveryProvider: packagesDiscoveryProvider);
-
- asyncTest(() => compiler.run(main).then((_) {
- Expect.equals(1, collector.errors.length,
- "Unexpected errors: ${collector.errors}");
- Expect.isTrue(checkError(collector.errors.first),
- "Unexpected error: ${collector.errors.first}");
- }));
+ Expect.equals(1, collector.errors.length,
+ "Unexpected errors: ${collector.errors}");
+ Expect.equals(expectedMessageKind, collector.errors.first.message.kind,
+ "Unexpected error: ${collector.errors.first}");
}
void main() {
- Uri script = currentDirectory.resolveUri(Platform.script);
- Uri packageRoot = script.resolve('./packages/');
+ asyncTest(() async {
+ Uri script = currentDirectory.resolveUri(Platform.script);
+ Uri packageRoot = script.resolve('./packages/');
- PackagesDiscoveryProvider noPackagesDiscovery = (Uri uri) {
- return new Future.value(Packages.noPackages);
- };
+ PackagesDiscoveryProvider noPackagesDiscovery = (Uri uri) {
+ return new Future.value(Packages.noPackages);
+ };
- bool containsErrorReading(DiagnosticMessage message) {
- return message.message.contains("Error reading ");
- }
+ await runTest(
+ Uri.parse('memory:main.dart'),
+ MessageKind.READ_SCRIPT_ERROR,
+ packageRoot: packageRoot);
+ await runTest(
+ Uri.parse('memory:main.dart'),
+ MessageKind.LIBRARY_NOT_FOUND,
+ packageConfig: PACKAGE_CONFIG_URI);
+ await runTest(
+ Uri.parse('memory:main.dart'),
+ MessageKind.LIBRARY_NOT_FOUND,
+ packagesDiscoveryProvider: noPackagesDiscovery);
- bool isLibraryNotFound(DiagnosticMessage message) {
- return message.message.startsWith("Library not found ");
- }
-
- runCompiler(Uri.parse('memory:main.dart'),
- containsErrorReading,
- packageRoot: packageRoot);
- runCompiler(Uri.parse('memory:main.dart'),
- isLibraryNotFound,
- packageConfig: PACKAGE_CONFIG_URI);
- runCompiler(Uri.parse('memory:main.dart'),
- isLibraryNotFound,
- packagesDiscoveryProvider: noPackagesDiscovery);
-
- runCompiler(Uri.parse('package:foo/foo.dart'),
- containsErrorReading,
- packageRoot: packageRoot);
- runCompiler(Uri.parse('package:foo/foo.dart'),
- isLibraryNotFound,
- packageConfig: PACKAGE_CONFIG_URI);
- runCompiler(Uri.parse('package:foo/foo.dart'),
- isLibraryNotFound,
- packagesDiscoveryProvider: noPackagesDiscovery);
+ await runTest(
+ Uri.parse('package:foo/foo.dart'),
+ MessageKind.READ_SELF_ERROR,
+ packageRoot: packageRoot);
+ await runTest(
+ Uri.parse('package:foo/foo.dart'),
+ MessageKind.LIBRARY_NOT_FOUND,
+ packageConfig: PACKAGE_CONFIG_URI);
+ await runTest(
+ Uri.parse('package:foo/foo.dart'),
+ MessageKind.LIBRARY_NOT_FOUND,
+ packagesDiscoveryProvider: noPackagesDiscovery);
+ });
}
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index ad7550c..4fe8790 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -42,23 +42,23 @@
void reportFatalError(Spannable node,
MessageKind errorCode,
[Map arguments]) {
- log(new Message(errorCode, arguments, false));
+ log(new Message(MessageTemplate.TEMPLATES[errorCode], arguments, false));
}
void reportError(Spannable node, MessageKind errorCode, [Map arguments]) {
- log(new Message(errorCode, arguments, false));
+ log(new Message(MessageTemplate.TEMPLATES[errorCode], arguments, false));
}
void reportWarning(Spannable node, MessageKind errorCode, [Map arguments]) {
- log(new Message(errorCode, arguments, false));
+ log(new Message(MessageTemplate.TEMPLATES[errorCode], arguments, false));
}
void reportInfo(Spannable node, MessageKind errorCode, [Map arguments]) {
- log(new Message(errorCode, arguments, false));
+ log(new Message(MessageTemplate.TEMPLATES[errorCode], arguments, false));
}
void reportHint(Spannable node, MessageKind errorCode, [Map arguments]) {
- log(new Message(errorCode, arguments, false));
+ log(new Message(MessageTemplate.TEMPLATES[errorCode], arguments, false));
}
withCurrentElement(Element element, f()) => f();
diff --git a/tests/compiler/dart2js/preserve_uris_test.dart b/tests/compiler/dart2js/preserve_uris_test.dart
index e0b8f1f..70d1d5e 100644
--- a/tests/compiler/dart2js/preserve_uris_test.dart
+++ b/tests/compiler/dart2js/preserve_uris_test.dart
@@ -6,7 +6,7 @@
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
-import 'memory_compiler.dart' show compilerFor, OutputCollector;
+import 'memory_compiler.dart' show runCompiler, OutputCollector;
const MEMORY_SOURCE_FILES = const <String, String> {
'main.dart': """
@@ -39,24 +39,22 @@
"""
};
-runTest(bool preserveUris) {
+runTest(bool preserveUris) async {
OutputCollector collector = new OutputCollector();
var options = ["--minify"];
if (preserveUris) options.add("--preserve-uris");
- var compiler = compilerFor(MEMORY_SOURCE_FILES,
- outputProvider: collector,
- options: options);
- return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
- String jsOutput = collector.getOutput('', 'js');
- Expect.equals(preserveUris, jsOutput.contains("main.dart"));
- Expect.equals(preserveUris, jsOutput.contains("lib.dart"));
- });
+ await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector,
+ options: options);
+ String jsOutput = collector.getOutput('', 'js');
+ Expect.equals(preserveUris, jsOutput.contains("main.dart"));
+ Expect.equals(preserveUris, jsOutput.contains("lib.dart"));
}
void main() {
- asyncStart();
- new Future.value()
- .then((_) => runTest(true))
- .then((_) => runTest(false))
- .whenComplete(asyncEnd);
+ asyncTest(() async {
+ await runTest(true);
+ await runTest(false);
+ });
}
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index c25eb93..35c2ded 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -308,7 +308,9 @@
.then((MockCompiler compiler) {
Expect.equals(1, compiler.errors.length);
Expect.equals(
- new Message(MessageKind.DUPLICATE_DEFINITION, {'name': 'foo'}, false),
+ new Message(
+ MessageTemplate.TEMPLATES[MessageKind.DUPLICATE_DEFINITION],
+ {'name': 'foo'}, false),
compiler.errors[0].message);
})], (f) => f());
}
@@ -491,7 +493,8 @@
Expect.equals(
new Message(
- MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': 'Foo'}, false),
+ MessageTemplate.TEMPLATES[MessageKind.CANNOT_RESOLVE_TYPE],
+ {'typeName': 'Foo'}, false),
compiler.warnings[0].message);
VariableDefinitions definition = compiler.parsedTree;
Expect.equals(warningNode, definition.type);
@@ -516,7 +519,8 @@
compiler.parseScript("class Foo extends Bar {}");
compiler.resolveStatement("Foo bar;");
Expect.equals(1, compiler.errors.length);
- var cannotResolveBar = new Message(MessageKind.CANNOT_EXTEND_MALFORMED,
+ var cannotResolveBar = new Message(
+ MessageTemplate.TEMPLATES[MessageKind.CANNOT_EXTEND_MALFORMED],
{'className': 'Foo', 'malformedType': 'Bar'}, false);
Expect.equals(cannotResolveBar, compiler.errors[0].message);
compiler.clearMessages();
@@ -544,7 +548,8 @@
Expect.equals(1, compiler.errors.length);
Expect.equals(
new Message(
- MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': 'var'}, false),
+ MessageTemplate.TEMPLATES[MessageKind.CANNOT_RESOLVE_TYPE],
+ {'typeName': 'var'}, false),
compiler.errors[0].message);
compiler.clearMessages();
});
@@ -557,7 +562,8 @@
Expect.equals(1, compiler.errors.length);
Expect.equals(
new Message(
- MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': 'bar'}, false),
+ MessageTemplate.TEMPLATES[MessageKind.CANNOT_RESOLVE_TYPE],
+ {'typeName': 'bar'}, false),
compiler.errors[0].message);
compiler.clearMessages();
diff --git a/tests/compiler/dart2js/semantic_visitor_test.dart b/tests/compiler/dart2js/semantic_visitor_test.dart
index 40b36ea..10833d3 100644
--- a/tests/compiler/dart2js/semantic_visitor_test.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test.dart
@@ -46,6 +46,7 @@
final target;
final targetType;
final initializers;
+ final error;
const Visit(this.method,
{this.element,
@@ -67,7 +68,8 @@
this.body,
this.target,
this.targetType,
- this.initializers});
+ this.initializers,
+ this.error});
int get hashCode => toString().hashCode;
@@ -136,6 +138,9 @@
if (initializers != null) {
sb.write(',initializers=$initializers');
}
+ if (error != null) {
+ sb.write(',error=$error');
+ }
return sb.toString();
}
}
@@ -211,6 +216,12 @@
// Constant expression are currently not computed during resolution.
VisitKind.VISIT_CONSTANT_GET,
VisitKind.VISIT_CONSTANT_INVOKE,
+ // TODO(johnniwinther): Test these when ResolverVisitor.visitSendSet has been
+ // rewritten.
+ VisitKind.ERROR_INVALID_SET,
+ VisitKind.ERROR_INVALID_PREFIX,
+ VisitKind.ERROR_INVALID_POSTFIX,
+ VisitKind.ERROR_INVALID_COMPOUND,
];
main(List<String> arguments) {
@@ -265,7 +276,7 @@
Future test(Set<VisitKind> unvisitedKinds,
List<String> arguments,
Map<String, List<Test>> TESTS,
- SemanticTestVisitor createVisitor(TreeElements elements)) {
+ SemanticTestVisitor createVisitor(TreeElements elements)) async {
Map<String, String> sourceFiles = {};
Map<String, Test> testMap = {};
StringBuffer mainSource = new StringBuffer();
@@ -296,71 +307,71 @@
mainSource.writeln("main() {}");
sourceFiles['main.dart'] = mainSource.toString();
- Compiler compiler = compilerFor(sourceFiles,
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: sourceFiles,
options: ['--analyze-all',
'--analyze-only',
'--enable-null-aware-operators']);
- return compiler.run(Uri.parse('memory:main.dart')).then((_) {
- testMap.forEach((String filename, Test test) {
- LibraryElement library = compiler.libraryLoader.lookupLibrary(
- Uri.parse('memory:$filename'));
- Element element;
- String cls = test.cls;
- String method = test.method;
- if (cls == null) {
- element = library.find(method);
- } else {
- ClassElement classElement = library.find(cls);
- Expect.isNotNull(classElement,
- "Class '$cls' not found in:\n"
- "${library.compilationUnit.script.text}");
- element = classElement.localLookup(method);
- }
- var expectedVisits = test.expectedVisits;
- if (expectedVisits == null) {
- Expect.isTrue(element.isErroneous,
- "Element '$method' expected to be have parse errors in:\n"
- "${library.compilationUnit.script.text}");
- return;
- } else if (expectedVisits is! List) {
- expectedVisits = [expectedVisits];
- }
- Expect.isFalse(element.isErroneous,
- "Element '$method' is not expected to be have parse errors in:\n"
+ Compiler compiler = result.compiler;
+ testMap.forEach((String filename, Test test) {
+ LibraryElement library = compiler.libraryLoader.lookupLibrary(
+ Uri.parse('memory:$filename'));
+ Element element;
+ String cls = test.cls;
+ String method = test.method;
+ if (cls == null) {
+ element = library.find(method);
+ } else {
+ ClassElement classElement = library.find(cls);
+ Expect.isNotNull(classElement,
+ "Class '$cls' not found in:\n"
+ "${library.compilationUnit.script.text}");
+ element = classElement.localLookup(method);
+ }
+ var expectedVisits = test.expectedVisits;
+ if (expectedVisits == null) {
+ Expect.isTrue(element.isErroneous,
+ "Element '$method' expected to be have parse errors in:\n"
"${library.compilationUnit.script.text}");
+ return;
+ } else if (expectedVisits is! List) {
+ expectedVisits = [expectedVisits];
+ }
+ Expect.isFalse(element.isErroneous,
+ "Element '$method' is not expected to be have parse errors in:\n"
+ "${library.compilationUnit.script.text}");
- void testAstElement(AstElement astElement) {
- Expect.isNotNull(astElement, "Element '$method' not found in:\n"
- "${library.compilationUnit.script.text}");
- ResolvedAst resolvedAst = astElement.resolvedAst;
- SemanticTestVisitor visitor = createVisitor(resolvedAst.elements);
- try {
- compiler.withCurrentElement(resolvedAst.element, () {
- //print(resolvedAst.node.toDebugString());
- resolvedAst.node.accept(visitor);
- });
- } catch (e, s) {
- Expect.fail("$e:\n$s\nIn test:\n"
- "${library.compilationUnit.script.text}");
- }
- Expect.listEquals(expectedVisits, visitor.visits,
- "In test:\n"
- "${library.compilationUnit.script.text}\n\n"
- "Expected: $expectedVisits\n"
- "Found: ${visitor.visits}");
- unvisitedKinds.removeAll(visitor.visits.map((visit) => visit.method));
+ void testAstElement(AstElement astElement) {
+ Expect.isNotNull(astElement, "Element '$method' not found in:\n"
+ "${library.compilationUnit.script.text}");
+ ResolvedAst resolvedAst = astElement.resolvedAst;
+ SemanticTestVisitor visitor = createVisitor(resolvedAst.elements);
+ try {
+ compiler.withCurrentElement(resolvedAst.element, () {
+ //print(resolvedAst.node.toDebugString());
+ resolvedAst.node.accept(visitor);
+ });
+ } catch (e, s) {
+ Expect.fail("$e:\n$s\nIn test:\n"
+ "${library.compilationUnit.script.text}");
}
- if (element.isAbstractField) {
- AbstractFieldElement abstractFieldElement = element;
- if (abstractFieldElement.getter != null) {
- testAstElement(abstractFieldElement.getter);
- } else if (abstractFieldElement.setter != null) {
- testAstElement(abstractFieldElement.setter);
- }
- } else {
- testAstElement(element);
+ Expect.listEquals(expectedVisits, visitor.visits,
+ "In test:\n"
+ "${library.compilationUnit.script.text}\n\n"
+ "Expected: $expectedVisits\n"
+ "Found: ${visitor.visits}");
+ unvisitedKinds.removeAll(visitor.visits.map((visit) => visit.method));
+ }
+ if (element.isAbstractField) {
+ AbstractFieldElement abstractFieldElement = element;
+ if (abstractFieldElement.getter != null) {
+ testAstElement(abstractFieldElement.getter);
+ } else if (abstractFieldElement.setter != null) {
+ testAstElement(abstractFieldElement.setter);
}
- });
+ } else {
+ testAstElement(element);
+ }
});
}
@@ -706,6 +717,21 @@
ERROR_INVALID_ASSERT,
ERROR_UNDEFINED_UNARY_EXPRESSION,
ERROR_UNDEFINED_BINARY_EXPRESSION,
+ ERROR_INVALID_GET,
+ ERROR_INVALID_INVOKE,
+ ERROR_INVALID_SET,
+ ERROR_INVALID_PREFIX,
+ ERROR_INVALID_POSTFIX,
+ ERROR_INVALID_COMPOUND,
+ ERROR_INVALID_UNARY,
+ ERROR_INVALID_EQUALS,
+ ERROR_INVALID_NOT_EQUALS,
+ ERROR_INVALID_BINARY,
+ ERROR_INVALID_INDEX,
+ ERROR_INVALID_INDEX_SET,
+ ERROR_INVALID_COMPOUND_INDEX_SET,
+ ERROR_INVALID_INDEX_PREFIX,
+ ERROR_INVALID_INDEX_POSTFIX,
VISIT_CONSTANT_GET,
VISIT_CONSTANT_INVOKE,
diff --git a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
index 9a420d6..d1fa072 100644
--- a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
@@ -268,8 +268,8 @@
class C {}
m() => C.this(null, 42);
''',
- const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
- name: 'this', arguments: '(null,42)')),
+ const Visit(VisitKind.ERROR_INVALID_INVOKE,
+ error: MessageKind.THIS_PROPERTY, arguments: '(null,42)')),
// TODO(johnniwinther): Expect [VISIT_FINAL_STATIC_FIELD_SET] instead.
const Test(
'''
@@ -744,6 +744,12 @@
name: 'o'),
],
isDeferred: true),
+ const Test.prefix(
+ '''
+ ''',
+ 'm() => p;',
+ const Visit(VisitKind.ERROR_INVALID_GET,
+ error: MessageKind.PREFIX_AS_EXPRESSION)),
const Test(
'''
var o;
@@ -956,6 +962,45 @@
const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
name: 'o',
arguments: '(null,42)')),
+ const Test.prefix(
+ '''
+ o(a, b) {}
+ ''',
+ 'm() => p.o(null, 42);',
+ const [
+ const Visit(VisitKind.PREVISIT_DEFERRED_ACCESS,
+ element: 'prefix(p)'),
+ const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INVOKE,
+ element: 'function(o)',
+ arguments: '(null,42)'),
+ ],
+ isDeferred: true),
+ const Test.prefix(
+ '''
+ ''',
+ 'm() => p.o(null, 42);',
+ const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
+ name: 'o',
+ arguments: '(null,42)')),
+ const Test.prefix(
+ '''
+ ''',
+ 'm() => p.o(null, 42);',
+ const [
+ const Visit(VisitKind.PREVISIT_DEFERRED_ACCESS,
+ element: 'prefix(p)'),
+ const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
+ name: 'o',
+ arguments: '(null,42)'),
+ ],
+ isDeferred: true),
+ const Test.prefix(
+ '''
+ ''',
+ 'm() => p(null, 42);',
+ const Visit(VisitKind.ERROR_INVALID_INVOKE,
+ error: MessageKind.PREFIX_AS_EXPRESSION,
+ arguments: '(null,42)')),
// TODO(johnniwinther): Expect [VISIT_TOP_LEVEL_FUNCTION_SET] instead.
const Test(
'''
@@ -1685,6 +1730,19 @@
''',
const Visit(VisitKind.ERROR_UNDEFINED_BINARY_EXPRESSION,
left: '2', operator: '!==', right: '3')),
+ const Test.clazz(
+ '''
+ class B {
+ operator +(_) => null;
+ }
+ class C extends B {
+ static m() => super + 42;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_BINARY,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ operator: '+',
+ right: '42')),
],
'Index': const [
// Index
@@ -1732,6 +1790,18 @@
'''
class B {
operator [](_) => null;
+ }
+ class C extends B {
+ static m() => super[42];
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_INDEX,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ index: '42')),
+ const Test.clazz(
+ '''
+ class B {
+ operator [](_) => null;
operator []=(a, b) {}
}
class C extends B {
@@ -1787,6 +1857,20 @@
operator []=(a, b) {}
}
class C extends B {
+ static m() => ++super[42];
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_INDEX_PREFIX,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ index: '42',
+ operator: '++')),
+ const Test.clazz(
+ '''
+ class B {
+ operator [](_) => null;
+ operator []=(a, b) {}
+ }
+ class C extends B {
m() => super[42]--;
}
''',
@@ -1832,6 +1916,20 @@
getter: 'function(B#[])',
index: '42',
operator: '--')),
+ const Test.clazz(
+ '''
+ class B {
+ operator [](_) => null;
+ operator []=(a, b) {}
+ }
+ class C extends B {
+ static m() => super[42]--;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_INDEX_POSTFIX,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ index: '42',
+ operator: '--')),
],
'Equals': const [
// Equals
@@ -1853,6 +1951,18 @@
const Visit(VisitKind.VISIT_SUPER_EQUALS,
element: 'function(B#==)',
right: '42')),
+ const Test.clazz(
+ '''
+ class B {
+ operator ==(_) => null;
+ }
+ class C extends B {
+ static m() => super == 42;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_EQUALS,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ right: '42')),
],
'Not equals': const [
// Not equals
@@ -1874,6 +1984,18 @@
const Visit(VisitKind.VISIT_SUPER_NOT_EQUALS,
element: 'function(B#==)',
right: '42')),
+ const Test.clazz(
+ '''
+ class B {
+ operator ==(_) => null;
+ }
+ class C extends B {
+ static m() => super != 42;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_NOT_EQUALS,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ right: '42')),
],
'Unary expression': const [
// Unary expression
@@ -1921,6 +2043,18 @@
''',
const Visit(VisitKind.VISIT_SUPER_UNARY,
element: 'function(B#~)', operator: '~')),
+ const Test.clazz(
+ '''
+ class B {
+ operator -() => null;
+ }
+ class C extends B {
+ static m() => -super;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_UNARY,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ operator: '-')),
const Test(
'''
m() => !0;
@@ -1964,6 +2098,17 @@
''',
const Visit(VisitKind.VISIT_UNRESOLVED_SUPER_INDEX_SET,
index: '1', rhs: '2')),
+ const Test.clazz(
+ '''
+ class B {
+ operator []=(a, b) {}
+ }
+ class C extends B {
+ static m() => super[1] = 2;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_INDEX_SET,
+ error: MessageKind.NO_SUPER_IN_STATIC, index: '1', rhs: '2')),
],
'Compound assignment': const [
// Compound assignment
@@ -2466,6 +2611,19 @@
const Visit(VisitKind.VISIT_UNRESOLVED_SUPER_SETTER_COMPOUND_INDEX_SET,
getter: 'function(B#[])',
index: '1', operator: '+=', rhs: '42')),
+ const Test.clazz(
+ '''
+ class B {
+ operator [](_) {}
+ operator []=(a, b) {}
+ }
+ class C extends B {
+ static m() => super[1] += 42;
+ }
+ ''',
+ const Visit(VisitKind.ERROR_INVALID_COMPOUND_INDEX_SET,
+ error: MessageKind.NO_SUPER_IN_STATIC,
+ index: '1', operator: '+=', rhs: '42')),
],
'Prefix expression': const [
// Prefix expression
diff --git a/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart b/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart
index 713a8c3..97531f3 100644
--- a/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart
@@ -38,6 +38,178 @@
}
@override
+ errorInvalidCompound(
+ Send node,
+ ErroneousElement error,
+ AssignmentOperator operator,
+ Node rhs,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_COMPOUND,
+ error: error.messageKind, operator: operator, rhs: rhs));
+ super.errorInvalidCompound(node, error, operator, rhs, arg);
+ }
+
+ @override
+ errorInvalidGet(
+ Send node,
+ ErroneousElement error,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_GET,
+ error: error.messageKind));
+ super.errorInvalidGet(node, error, arg);
+ }
+
+ @override
+ errorInvalidInvoke(
+ Send node,
+ ErroneousElement error,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_INVOKE,
+ error: error.messageKind, arguments: arguments));
+ super.errorInvalidInvoke(node, error, arguments, selector, arg);
+ }
+
+ @override
+ errorInvalidPostfix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_POSTFIX,
+ error: error.messageKind, operator: operator));
+ super.errorInvalidPostfix(node, error, operator, arg);
+ }
+
+ @override
+ errorInvalidPrefix(
+ Send node,
+ ErroneousElement error,
+ IncDecOperator operator,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_PREFIX,
+ error: error.messageKind, operator: operator));
+ super.errorInvalidPrefix(node, error, operator, arg);
+ }
+
+ @override
+ errorInvalidSet(
+ Send node,
+ ErroneousElement error,
+ Node rhs,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_SET,
+ error: error.messageKind, rhs: rhs));
+ super.errorInvalidSet(node, error, rhs, arg);
+ }
+
+ @override
+ errorInvalidUnary(
+ Send node,
+ UnaryOperator operator,
+ ErroneousElement error,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_UNARY,
+ error: error.messageKind, operator: operator));
+ super.errorInvalidUnary(node, operator, error, arg);
+ }
+
+ @override
+ errorInvalidEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_EQUALS,
+ error: error.messageKind, right: right));
+ super.errorInvalidEquals(node, error, right, arg);
+ }
+
+ @override
+ errorInvalidNotEquals(
+ Send node,
+ ErroneousElement error,
+ Node right,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_NOT_EQUALS,
+ error: error.messageKind, right: right));
+ super.errorInvalidNotEquals(node, error, right, arg);
+ }
+
+ @override
+ errorInvalidBinary(
+ Send node,
+ ErroneousElement error,
+ BinaryOperator operator,
+ Node right,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_BINARY,
+ error: error.messageKind, operator: operator, right: right));
+ super.errorInvalidBinary(node, error, operator, right, arg);
+ }
+
+ @override
+ errorInvalidIndex(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_INDEX,
+ error: error.messageKind, index: index));
+ super.errorInvalidIndex(node, error, index, arg);
+ }
+
+ @override
+ errorInvalidIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ Node rhs,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_INDEX_SET,
+ error: error.messageKind, index: index, rhs: rhs));
+ super.errorInvalidIndexSet(node, error, index, rhs, arg);
+ }
+
+ @override
+ errorInvalidCompoundIndexSet(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ AssignmentOperator operator,
+ Node rhs,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_COMPOUND_INDEX_SET,
+ error: error.messageKind, index: index, operator: operator, rhs: rhs));
+ super.errorInvalidCompoundIndexSet(node, error, index, operator, rhs, arg);
+ }
+
+ @override
+ errorInvalidIndexPrefix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_INDEX_PREFIX,
+ error: error.messageKind, index: index, operator: operator));
+ super.errorInvalidIndexPrefix(node, error, index, operator, arg);
+ }
+
+ @override
+ errorInvalidIndexPostfix(
+ Send node,
+ ErroneousElement error,
+ Node index,
+ IncDecOperator operator,
+ arg) {
+ visits.add(new Visit(VisitKind.ERROR_INVALID_INDEX_POSTFIX,
+ error: error.messageKind, index: index, operator: operator));
+ super.errorInvalidIndexPostfix(node, error, index, operator, arg);
+ }
+
+ @override
visitBinary(
Send node,
Node left,
diff --git a/tests/compiler/dart2js/serialization_analysis_test.dart b/tests/compiler/dart2js/serialization_analysis_test.dart
index 775f6741..147c82b 100644
--- a/tests/compiler/dart2js/serialization_analysis_test.dart
+++ b/tests/compiler/dart2js/serialization_analysis_test.dart
@@ -176,12 +176,15 @@
Deserializer deserializer = new Deserializer.fromText(
serializedData, const JsonSerializationDecoder());
DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
- Compiler compiler = compilerFor(
- test != null ? test.sourceFiles : const {},
+ await runCompiler(
+ entryPoint: entryPoint,
+ memorySourceFiles: test != null ? test.sourceFiles : const {},
options: ['--analyze-only', '--output-type=dart'],
- diagnosticHandler: diagnosticCollector);
- compiler.serialization.deserializer = new _DeserializerSystem(deserializer);
- await compiler.runCompiler(entryPoint);
+ diagnosticHandler: diagnosticCollector,
+ beforeRun: (Compiler compiler) {
+ compiler.serialization.deserializer =
+ new _DeserializerSystem(deserializer);
+ });
if (test != null) {
Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
"Unexpected error count.");
diff --git a/tests/compiler/dart2js/serialization_test.dart b/tests/compiler/dart2js/serialization_test.dart
index a258c2d..5f4b19b 100644
--- a/tests/compiler/dart2js/serialization_test.dart
+++ b/tests/compiler/dart2js/serialization_test.dart
@@ -43,9 +43,10 @@
if (entryPoint == null) {
entryPoint = Uri.parse('dart:core');
}
- Compiler compiler = compilerFor({}, options: ['--analyze-all']);
asyncTest(() async {
- await compiler.runCompiler(entryPoint);
+ CompilationResult result = await runCompiler(
+ entryPoint: entryPoint, options: ['--analyze-all']);
+ Compiler compiler = result.compiler;
testSerialization(compiler.libraryLoader.libraries,
outPath: outPath,
prettyPrint: prettyPrint);
diff --git a/tests/compiler/dart2js/show_package_warnings_test.dart b/tests/compiler/dart2js/show_package_warnings_test.dart
index de518f9..5673032 100644
--- a/tests/compiler/dart2js/show_package_warnings_test.dart
+++ b/tests/compiler/dart2js/show_package_warnings_test.dart
@@ -4,9 +4,9 @@
// Test that the '--show-package-warnings' option works as intended.
+import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
-
import 'memory_compiler.dart';
/// Error code that creates 1 warning, 1 hint, and 1 info.
@@ -42,42 +42,36 @@
import 'package:pkg_error2/pkg_error2.dart';
"""};
-void test(List<Uri> entryPoints,
- {bool showPackageWarnings: false,
- int warnings: 0,
- int hints: 0,
- int infos: 0}) {
+Future test(Uri entryPoint,
+ {bool showPackageWarnings: false,
+ int warnings: 0,
+ int hints: 0,
+ int infos: 0}) async {
var options = ['--analyze-only', '--analyze-all'];
if (showPackageWarnings) {
options.add('--show-package-warnings');
}
var collector = new DiagnosticCollector();
- var compiler = compilerFor(SOURCE,
- options: options,
- packageRoot: Uri.parse('memory:pkg/'),
- diagnosticHandler: collector);
- Uri mainUri = null;
- if (entryPoints.length == 1) {
- mainUri = entryPoints[0];
- } else {
- compiler.librariesToAnalyzeWhenRun = entryPoints;
- }
- asyncTest(() => compiler.run(mainUri).then((_) {
- print('==================================================================');
- print('test: $entryPoints showPackageWarnings=$showPackageWarnings');
- Expect.equals(0, collector.errors.length,
- 'Unexpected errors: ${collector.errors}');
- Expect.equals(warnings, collector.warnings.length,
- 'Unexpected warnings: ${collector.warnings}');
- checkUriSchemes(collector.warnings);
- Expect.equals(hints, collector.hints.length,
- 'Unexpected hints: ${collector.hints}');
- checkUriSchemes(collector.hints);
- Expect.equals(infos, collector.infos.length,
- 'Unexpected infos: ${collector.infos}');
- checkUriSchemes(collector.infos);
- print('==================================================================');
- }));
+ await runCompiler(
+ entryPoint: entryPoint,
+ memorySourceFiles: SOURCE,
+ options: options,
+ packageRoot: Uri.parse('memory:pkg/'),
+ diagnosticHandler: collector);
+ print('==================================================================');
+ print('test: $entryPoint showPackageWarnings=$showPackageWarnings');
+ Expect.equals(0, collector.errors.length,
+ 'Unexpected errors: ${collector.errors}');
+ Expect.equals(warnings, collector.warnings.length,
+ 'Unexpected warnings: ${collector.warnings}');
+ checkUriSchemes(collector.warnings);
+ Expect.equals(hints, collector.hints.length,
+ 'Unexpected hints: ${collector.hints}');
+ checkUriSchemes(collector.hints);
+ Expect.equals(infos, collector.infos.length,
+ 'Unexpected infos: ${collector.infos}');
+ checkUriSchemes(collector.infos);
+ print('==================================================================');
}
void checkUriSchemes(Iterable<DiagnosticMessage> messages) {
@@ -90,28 +84,36 @@
}
void main() {
- test([Uri.parse('memory:main.dart')],
- showPackageWarnings: true,
- // From error.dart, package:pkg_error1 and package:pkg_error2:
- warnings: 3, hints: 3, infos: 3);
- test([Uri.parse('memory:main.dart')],
- showPackageWarnings: false,
- // From error.dart only:
- warnings: 1, hints: 1 + 2 /* from summary */, infos: 1);
- test([Uri.parse('package:pkg_error1/pkg_error1.dart')],
- showPackageWarnings: true,
- // From package:pkg_error1 and package:pkg_error2:
- warnings: 2, hints: 2, infos: 2);
- test([Uri.parse('package:pkg_error1/pkg_error1.dart')],
- showPackageWarnings: false,
- // From package:pkg_error1/pkg_error1.dart only:
- warnings: 1, hints: 1 + 1 /* from summary */, infos: 1);
- test([Uri.parse('package:pkg_noerror/pkg_noerror.dart')],
- showPackageWarnings: true,
- // From package:pkg_error1 and package:pkg_error2:
- warnings: 2, hints: 2, infos: 2);
- test([Uri.parse('package:pkg_noerror/pkg_noerror.dart')],
- showPackageWarnings: false,
- hints: 2 /* from summary */);
+ asyncTest(() async {
+ await test(
+ Uri.parse('memory:main.dart'),
+ showPackageWarnings: true,
+ // From error.dart, package:pkg_error1 and package:pkg_error2:
+ warnings: 3, hints: 3, infos: 3);
+ await test(
+ Uri.parse('memory:main.dart'),
+ showPackageWarnings: false,
+ // From error.dart only:
+ warnings: 1, hints: 1 + 2 /* from summary */, infos: 1);
+ await test(
+ Uri.parse('package:pkg_error1/pkg_error1.dart'),
+ showPackageWarnings: true,
+ // From package:pkg_error1 and package:pkg_error2:
+ warnings: 2, hints: 2, infos: 2);
+ await test(
+ Uri.parse('package:pkg_error1/pkg_error1.dart'),
+ showPackageWarnings: false,
+ // From package:pkg_error1/pkg_error1.dart only:
+ warnings: 1, hints: 1 + 1 /* from summary */, infos: 1);
+ await test(
+ Uri.parse('package:pkg_noerror/pkg_noerror.dart'),
+ showPackageWarnings: true,
+ // From package:pkg_error1 and package:pkg_error2:
+ warnings: 2, hints: 2, infos: 2);
+ await test(
+ Uri.parse('package:pkg_noerror/pkg_noerror.dart'),
+ showPackageWarnings: false,
+ hints: 2 /* from summary */);
+ });
}
diff --git a/tests/compiler/dart2js/source_map_name_test.dart b/tests/compiler/dart2js/source_map_name_test.dart
index 110fff5..46aeb86 100644
--- a/tests/compiler/dart2js/source_map_name_test.dart
+++ b/tests/compiler/dart2js/source_map_name_test.dart
@@ -81,8 +81,9 @@
main() {
asyncTest(() async {
- Compiler compiler = compilerFor({'main.dart': SOURCE});
- await compiler.run(Uri.parse('memory:main.dart'));
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: {'main.dart': SOURCE});
+ Compiler compiler = result.compiler;
Element lookup(String name) {
Element element;
diff --git a/tests/compiler/dart2js/source_map_test.dart b/tests/compiler/dart2js/source_map_test.dart
index 021eb2e..3d3c2ea 100644
--- a/tests/compiler/dart2js/source_map_test.dart
+++ b/tests/compiler/dart2js/source_map_test.dart
@@ -30,7 +30,7 @@
}
}
-void test({String out, String sourceMap, String mapping, String file}) {
+test({String out, String sourceMap, String mapping, String file}) async {
OutputCollector collector = new OutputCollector();
List<String> options = <String>[];
if (out != null) {
@@ -39,35 +39,37 @@
if (sourceMap != null) {
options.add("--source-map=$sourceMap");
}
- var compiler = compilerFor(SOURCE,
- showDiagnostics: true,
- outputProvider: collector,
- options: options);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:/main.dart')).then(
- (_) {
- String jsOutput = collector.getOutput('', 'js');
- Expect.isNotNull(jsOutput);
- if (mapping != null) {
- find(jsOutput, '//# sourceMappingURL=$mapping', true);
- } else {
- find(jsOutput, '//# sourceMappingURL=', false);
- }
- String jsSourceMapOutput = collector.getOutput('', 'js.map');
- Expect.isNotNull(jsSourceMapOutput);
- if (file != null) {
- find(jsSourceMapOutput, '"file": "$file"', true);
- } else {
- find(jsSourceMapOutput, '"file": ', false);
- }
- }));
+
+ await runCompiler(
+ entryPoint: Uri.parse('memory:/main.dart'),
+ memorySourceFiles: SOURCE,
+ showDiagnostics: true,
+ outputProvider: collector,
+ options: options);
+ String jsOutput = collector.getOutput('', 'js');
+ Expect.isNotNull(jsOutput);
+ if (mapping != null) {
+ find(jsOutput, '//# sourceMappingURL=$mapping', true);
+ } else {
+ find(jsOutput, '//# sourceMappingURL=', false);
+ }
+ String jsSourceMapOutput = collector.getOutput('', 'js.map');
+ Expect.isNotNull(jsSourceMapOutput);
+ if (file != null) {
+ find(jsSourceMapOutput, '"file": "$file"', true);
+ } else {
+ find(jsSourceMapOutput, '"file": ', false);
+ }
}
void main() {
- test();
- test(sourceMap: 'file:/out.js.map');
- test(out: 'file:/out.js');
- test(out: 'file:/out.js', sourceMap: 'file:/out.js.map',
- file: 'out.js', mapping: 'out.js.map');
- test(out: 'file:/dir/out.js', sourceMap: 'file:/dir/out.js.map',
- file: 'out.js', mapping: 'out.js.map');
+ asyncTest(() async {
+ await test();
+ await test(sourceMap: 'file:/out.js.map');
+ await test(out: 'file:/out.js');
+ await test(out: 'file:/out.js', sourceMap: 'file:/out.js.map',
+ file: 'out.js', mapping: 'out.js.map');
+ await test(out: 'file:/dir/out.js', sourceMap: 'file:/dir/out.js.map',
+ file: 'out.js', mapping: 'out.js.map');
+ });
}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/colors.dart b/tests/compiler/dart2js/sourcemaps/colors.dart
index 8241dd1..10aa511 100644
--- a/tests/compiler/dart2js/sourcemaps/colors.dart
+++ b/tests/compiler/dart2js/sourcemaps/colors.dart
@@ -8,8 +8,8 @@
/// A web color.
abstract class Color {
- /// The hexadecimal code for the color, without the prefixed '#'.
- String get toHex;
+ /// The css code for the color.
+ String get toCss;
}
/// A web color defined as RGB.
@@ -22,8 +22,9 @@
/// all in range 0..1.
const RGB(this.r, this.g, this.b);
- String get toHex {
+ String get toCss {
StringBuffer sb = new StringBuffer();
+ sb.write('#');
void writeHex(double value) {
int i = (value * 255.0).round();
@@ -43,6 +44,37 @@
String toString() => 'rgb($r,$g,$b)';
}
+class RGBA extends RGB {
+ final double a;
+
+ const RGBA(double r, double g, double b, this.a) : super(r, g, b);
+
+ String get toCss {
+ StringBuffer sb = new StringBuffer();
+
+ void writeInt(double value) {
+ int i = (value * 255.0).round();
+ if (i < 16) {
+ sb.write('0');
+ }
+ sb.write(i);
+ }
+
+ sb.write('rgba(');
+ writeInt(r);
+ sb.write(', ');
+ writeInt(g);
+ sb.write(', ');
+ writeInt(b);
+ sb.write(', ');
+ sb.write(a);
+ sb.write(')');
+
+ return sb.toString();
+ }
+
+}
+
/// A web color defined as HSV.
class HSV implements Color {
final double h;
@@ -53,7 +85,7 @@
/// saturation [s] in range 0..1, and value [v] in range 0..1.
const HSV(this.h, this.s, this.v);
- String get toHex => toRGB(this).toHex;
+ String get toCss => toRGB(this).toCss;
static RGB toRGB(HSV hsv) {
double h = hsv.h;
diff --git a/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart b/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
index 83a5ef3..91670bc 100644
--- a/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
+++ b/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
@@ -5,7 +5,6 @@
// Test file for testing source mappings of invocations.
var counter = 0;
-var bucket;
main(args) {
counter++;
diff --git a/tests/compiler/dart2js/sourcemaps/operators_test_file.dart b/tests/compiler/dart2js/sourcemaps/operators_test_file.dart
new file mode 100644
index 0000000..bbd85c0
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/operators_test_file.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test file for testing source mappings of operations.
+
+var counter = 0;
+
+void record(result) {
+ counter++;
+}
+
+main(args) {
+ counter++;
+ operations(args.length > 0,
+ 0, 1.5, args[0], new Complex(0, 1), new Complex(1.5, 2.5));
+ return counter;
+}
+
+void operations(cond, a, b, c, d, e) {
+ if (cond) record(a + a);
+ if (cond) record(a + b);
+ if (cond) record(a + c);
+ if (cond) record(a + d);
+ if (cond) record(a + e);
+ if (cond) record(b + a);
+ if (cond) record(b + b);
+ if (cond) record(b + c);
+ if (cond) record(b + d);
+ if (cond) record(b + e);
+ if (cond) record(c + a);
+ if (cond) record(c + b);
+ if (cond) record(c + c);
+ if (cond) record(c + d);
+ if (cond) record(c + e);
+ if (cond) record(d + a);
+ if (cond) record(d + b);
+ if (cond) record(d + c);
+ if (cond) record(d + d);
+ if (cond) record(d + e);
+ if (cond) record(e + a);
+ if (cond) record(e + b);
+ if (cond) record(e + c);
+ if (cond) record(e + d);
+ if (cond) record(e + e);
+}
+
+class Complex {
+ final num re;
+ final num im;
+
+ const Complex(this.re, this.im);
+
+ operator +(Complex other) => new Complex(re + other.re, im + other.im);
+
+ // TODO(johnniwinther): Support implicit null check in '=='.
+ //operator ==(Complex other) => re == other.re && im == other.im;
+
+ int get hashCode => 13 * re.hashCode + 17 * im.hashCode;
+}
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_invokes_test.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_invokes_test.dart
new file mode 100644
index 0000000..20359e4
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_invokes_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'source_mapping_tester.dart' as tester;
+
+void main() {
+ tester.main(['invokes']);
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_operators_test.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_operators_test.dart
new file mode 100644
index 0000000..908ef87
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_operators_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'source_mapping_tester.dart' as tester;
+
+void main() {
+ tester.main(['operators']);
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
deleted file mode 100644
index 551bf40..0000000
--- a/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
-import 'sourcemap_helper.dart';
-import 'sourcemap_html_helper.dart';
-import 'package:compiler/src/filenames.dart';
-
-main(List<String> arguments) {
- bool showAll = false;
- bool measure = false;
- Uri outputUri;
- Set<String> configurations = new Set<String>();
- for (String argument in arguments) {
- if (argument.startsWith('-')) {
- if (argument == '-a') {
- /// Generate visualization for all user methods.
- showAll = true;
- } else if (argument == '-m') {
- /// Measure instead of reporting the number of missing code points.
- measure = true;
- } else if (argument.startsWith('--out=')) {
- /// Generate visualization for the first configuration.
- outputUri = Uri.base.resolve(
- nativeToUriPath(argument.substring('--out='.length)));
- } else if (argument.startsWith('-o')) {
- /// Generate visualization for the first configuration.
- outputUri = Uri.base.resolve(
- nativeToUriPath(argument.substring('-o'.length)));
- } else {
- print("Unknown option '$argument'.");
- return;
- }
- } else {
- if (TEST_CONFIGURATIONS.containsKey(argument)) {
- configurations.add(argument);
- } else {
- print("Unknown configuration '$argument'. "
- "Must be one of '${TEST_CONFIGURATIONS.keys.join("', '")}'");
- return;
- }
- }
- }
-
- if (configurations.isEmpty) {
- configurations.addAll(TEST_CONFIGURATIONS.keys);
- }
- String outputConfig = configurations.first;
-
- asyncTest(() async {
- List<Measurement> measurements = <Measurement>[];
- for (String config in configurations) {
- List<String> options = TEST_CONFIGURATIONS[config];
- Measurement measurement = await runTests(
- config,
- options,
- showAll: showAll,
- measure: measure,
- outputUri: outputConfig == config ? outputUri : null);
- if (measurement != null) {
- measurements.add(measurement);
- }
- }
- for (Measurement measurement in measurements) {
- print(measurement);
- }
- });
-}
-
-const Map<String, List<String>> TEST_CONFIGURATIONS = const {
- 'old': const [],
- 'ssa': const ['--use-new-source-info', ],
- 'cps': const ['--use-new-source-info', '--use-cps-ir'],
-};
-
-Future<Measurement> runTests(
- String config,
- List<String> options,
- {bool showAll: false,
- Uri outputUri,
- bool measure: false}) async {
- if (config == 'old' && !measure) return null;
-
- String filename =
- 'tests/compiler/dart2js/sourcemaps/invokes_test_file.dart';
- SourceMapProcessor processor = new SourceMapProcessor(filename);
- List<SourceMapInfo> infoList = await processor.process(
- ['--csp', '--disable-inlining']
- ..addAll(options),
- verbose: !measure);
- List<SourceMapInfo> userInfoList = <SourceMapInfo>[];
- List<SourceMapInfo> failureList = <SourceMapInfo>[];
- Measurement measurement = new Measurement(config);
- for (SourceMapInfo info in infoList) {
- if (info.element.library.isPlatformLibrary) continue;
- userInfoList.add(info);
- Iterable<CodePoint> missingCodePoints =
- info.codePoints.where((c) => c.isMissing);
- measurement.missing += missingCodePoints.length;
- measurement.count += info.codePoints.length;
- if (!measure) {
- if (!missingCodePoints.isEmpty) {
- print("Missing code points for ${info.element} in '$filename':");
- for (CodePoint codePoint in missingCodePoints) {
- print(" $codePoint");
- }
- failureList.add(info);
- }
- }
- }
- if (failureList.isNotEmpty) {
- if (outputUri == null) {
- if (!measure) {
- Expect.fail(
- "Missing code points found. "
- "Run the test with a URI option, "
- "`source_mapping_test --out=<uri> $config`, to "
- "create a html visualization of the missing code points.");
- }
- } else {
- createTraceSourceMapHtml(outputUri, processor,
- showAll ? userInfoList : failureList);
- }
- } else if (outputUri != null) {
- createTraceSourceMapHtml(outputUri, processor, userInfoList);
- }
- return measurement;
-}
-
-class Measurement {
- final String config;
- int missing = 0;
- int count = 0;
-
- Measurement(this.config);
-
- String toString() {
- double percentage = 100 * missing / count;
- return "Config '${config}': $missing of $count ($percentage%) missing";
- }
-}
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_test_viewer.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_test_viewer.dart
new file mode 100644
index 0000000..4691568
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_test_viewer.dart
@@ -0,0 +1,166 @@
+// 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.
+
+/// Visualization of source mappings generated and tested in
+/// 'source_mapping_test.dart'.
+
+library source_mapping.test.viewer;
+
+import 'dart:async';
+import 'package:compiler/src/filenames.dart';
+import 'package:compiler/src/util/util.dart';
+import 'source_mapping_tester.dart';
+import 'sourcemap_helper.dart';
+import 'sourcemap_html_helper.dart';
+import 'sourcemap_html_templates.dart';
+
+const String DEFAULT_OUTPUT_PATH = 'out.js.map.html';
+
+main(List<String> arguments) async {
+ bool measure = false;
+ String outputPath = DEFAULT_OUTPUT_PATH;
+ Set<String> configurations = new Set<String>();
+ Set<String> files = new Set<String>();
+ for (String argument in arguments) {
+ if (argument.startsWith('-')) {
+ if (argument == '-m') {
+ /// Measure instead of reporting the number of missing code points.
+ measure = true;
+ } else if (argument.startsWith('--out=')) {
+ /// Generate visualization for the first configuration.
+ outputPath = argument.substring('--out='.length);
+
+ } else if (argument.startsWith('-o')) {
+ /// Generate visualization for the first configuration.
+ outputPath = argument.substring('-o'.length);
+ } else {
+ print("Unknown option '$argument'.");
+ return;
+ }
+ } else {
+ if (!parseArgument(argument, configurations, files)) {
+ return;
+ }
+ }
+ }
+
+ if (configurations.isEmpty) {
+ configurations.addAll(TEST_CONFIGURATIONS.keys);
+ if (!measure) {
+ configurations.remove('old');
+ }
+ }
+ if (files.isEmpty) {
+ files.addAll(TEST_FILES.keys);
+ }
+
+ OutputConfigurations outputConfigurations =
+ new OutputConfigurations(configurations, files);
+ bool generateMultiConfigs = false;
+ if (outputPath != null) {
+ if (configurations.length > 1 || files.length > 1) {
+ for (String config in configurations) {
+ for (String file in files) {
+ String path = '$outputPath.$config.$file';
+ Uri uri = Uri.base.resolve(nativeToUriPath(path));
+ outputConfigurations.registerPathUri(config, file, path, uri);
+ }
+ }
+ generateMultiConfigs = true;
+ } else {
+ outputConfigurations.registerPathUri(
+ configurations.first,
+ files.first,
+ outputPath,
+ Uri.base.resolve(nativeToUriPath(outputPath)));
+ }
+ }
+
+ List<Measurement> measurements = <Measurement>[];
+ for (String config in configurations) {
+ List<String> options = TEST_CONFIGURATIONS[config];
+ for (String file in files) {
+ Measurement measurement = await runTest(
+ config, TEST_FILES[file], options,
+ outputUri: outputConfigurations.getUri(config, file),
+ verbose: !measure);
+ measurements.add(measurement);
+ }
+ }
+ for (Measurement measurement in measurements) {
+ print(measurement);
+ }
+ if (generateMultiConfigs) {
+ outputMultiConfigs(
+ Uri.base.resolve(outputPath),
+ outputConfigurations);
+ }
+}
+
+class OutputConfigurations implements Configurations {
+ final Iterable<String> configs;
+ final Iterable<String> files;
+ final Map<Pair, String> pathMap = {};
+ final Map<Pair, Uri> uriMap = {};
+
+ OutputConfigurations(this.configs, this.files);
+
+ void registerPathUri(String config, String file, String path, Uri uri) {
+ Pair key = new Pair(config, file);
+ pathMap[key] = path;
+ uriMap[key] = uri;
+ }
+
+ Uri getUri(String config, String file) {
+ Pair key = new Pair(config, file);
+ return uriMap[key];
+ }
+
+ @override
+ String getPath(String config, String file) {
+ Pair key = new Pair(config, file);
+ return pathMap[key];
+ }
+}
+
+Future<Measurement> runTest(
+ String config,
+ String filename,
+ List<String> options,
+ {Uri outputUri,
+ bool verbose}) async {
+ TestResult result =
+ await runTests(config, filename, options, verbose: verbose);
+ if (outputUri != null) {
+ if (result.failureMap.isNotEmpty) {
+ result.failureMap.forEach((info, missingCodePoints) {
+ print("Missing code points for ${info.element} in '$filename' "
+ "in config '$config':");
+ for (CodePoint codePoint in missingCodePoints) {
+ print(" $codePoint");
+ }
+ });
+ }
+ createTraceSourceMapHtml(outputUri, result.processor, result.userInfoList);
+ }
+ return new Measurement(config, filename,
+ result.failureMap.values.fold(0, (s, i) => s + i.length),
+ result.userInfoList.fold(0, (s, i) => s + i.codePoints.length));
+}
+
+class Measurement {
+ final String config;
+ final String filename;
+
+ final int missing;
+ final int count;
+
+ Measurement(this.config, this.filename, this.missing, this.count);
+
+ String toString() {
+ double percentage = 100 * missing / count;
+ return "Config '${config}', file: '${filename}': "
+ "$missing of $count ($percentage%) missing";
+ }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
new file mode 100644
index 0000000..9e7d5b6
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'sourcemap_helper.dart';
+
+main(List<String> arguments) {
+ Set<String> configurations = new Set<String>();
+ Set<String> files = new Set<String>();
+ for (String argument in arguments) {
+ if (!parseArgument(argument, configurations, files)) {
+ return;
+ }
+ }
+
+ if (configurations.isEmpty) {
+ configurations.addAll(TEST_CONFIGURATIONS.keys);
+ configurations.remove('old');
+ }
+ if (files.isEmpty) {
+ files.addAll(TEST_FILES.keys);
+ }
+
+ asyncTest(() async {
+ bool missingCodePointsFound = false;
+ for (String config in configurations) {
+ List<String> options = TEST_CONFIGURATIONS[config];
+ for (String file in files) {
+ String filename = TEST_FILES[file];
+ TestResult result = await runTests(config, filename, options);
+ if (result.failureMap.isNotEmpty) {
+ result.failureMap.forEach((info, missingCodePoints) {
+ print("Missing code points for ${info.element} in '$filename' "
+ "in config '$config':");
+ for (CodePoint codePoint in missingCodePoints) {
+ print(" $codePoint");
+ }
+ });
+ missingCodePointsFound = true;
+ }
+ }
+ }
+ Expect.isFalse(missingCodePointsFound,
+ "Missing code points found. "
+ "Run the test with a URI option, "
+ "`source_mapping_test_viewer [--out=<uri>] [configs] [tests]`, to "
+ "create a html visualization of the missing code points.");
+ });
+}
+
+/// Parse [argument] for a valid configuration or test-file option.
+///
+/// On success, the configuration name is added to [configurations] or the
+/// test-file name is added to [files], and `true` is returned.
+/// On failure, a message is printed and `false` is returned.
+///
+bool parseArgument(String argument,
+ Set<String> configurations,
+ Set<String> files) {
+ if (TEST_CONFIGURATIONS.containsKey(argument)) {
+ configurations.add(argument);
+ } else if (TEST_FILES.containsKey(argument)) {
+ files.add(argument);
+ } else {
+ print("Unknown configuration or file '$argument'. "
+ "Must be one of '${TEST_CONFIGURATIONS.keys.join("', '")}' or "
+ "'${TEST_FILES.keys.join("', '")}'.");
+ return false;
+ }
+ return true;
+}
+
+const Map<String, List<String>> TEST_CONFIGURATIONS = const {
+ 'ssa': const ['--use-new-source-info', ],
+ 'cps': const ['--use-new-source-info', '--use-cps-ir'],
+ 'old': const [],
+};
+
+const Map<String, String> TEST_FILES = const <String, String>{
+ 'invokes': 'tests/compiler/dart2js/sourcemaps/invokes_test_file.dart',
+ 'operators': 'tests/compiler/dart2js/sourcemaps/operators_test_file.dart',
+};
+
+Future<TestResult> runTests(
+ String config,
+ String filename,
+ List<String> options,
+ {bool verbose: true}) async {
+ SourceMapProcessor processor = new SourceMapProcessor(filename);
+ List<SourceMapInfo> infoList = await processor.process(
+ ['--csp', '--disable-inlining']
+ ..addAll(options),
+ verbose: verbose);
+ TestResult result = new TestResult(config, filename, processor);
+ for (SourceMapInfo info in infoList) {
+ if (info.element.library.isPlatformLibrary) continue;
+ result.userInfoList.add(info);
+ Iterable<CodePoint> missingCodePoints =
+ info.codePoints.where((c) => c.isMissing);
+ if (missingCodePoints.isNotEmpty) {
+ result.failureMap[info] = missingCodePoints;
+ }
+ }
+ return result;
+}
+
+class TestResult {
+ final String config;
+ final String file;
+ final SourceMapProcessor processor;
+ List<SourceMapInfo> userInfoList = <SourceMapInfo>[];
+ Map<SourceMapInfo, Iterable<CodePoint>> failureMap =
+ <SourceMapInfo, Iterable<CodePoint>>{};
+
+ TestResult(this.config, this.file, this.processor);
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
index 697bf02..1dbbc1f 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -256,7 +256,7 @@
addLocation(null, nodeToString(node));
} else {
locationMap.forEach((int targetOffset, List<SourceLocation> locations) {
- String jsCode = positionToString(targetOffset);
+ String jsCode = nodeToString(node);
for (SourceLocation location in locations) {
addLocation(location, jsCode);
}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
index eb1399a..4227fee 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -18,14 +18,26 @@
import 'sourcemap_html_templates.dart';
/// Returns the [index]th color for visualization.
-String toColor(int index) {
+HSV toColor(int index) {
int hueCount = 24;
double h = 360.0 * (index % hueCount) / hueCount;
double v = 1.0;
double s = 0.5;
- HSV hsv = new HSV(h, s, v);
- RGB rgb = HSV.toRGB(hsv);
- return rgb.toHex;
+ return new HSV(h, s, v);
+}
+
+/// Return the CSS color value for the [index]th color.
+String toColorCss(int index) {
+ return toColor(index).toCss;
+}
+
+/// Return the CSS color value for the [index]th span.
+String toPattern(int index) {
+ /// Use gradient on spans to visually identify consecutive spans mapped to the
+ /// same source location.
+ HSV startColor = toColor(index);
+ HSV endColor = new HSV(startColor.h, startColor.s + 0.4, startColor.v - 0.2);
+ return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})';
}
/// Return the html for the [index] line number.
@@ -131,7 +143,7 @@
SourceLocation sourceLocation = lastSourceLocations.single;
if (sourceLocation != null) {
index = collection.getIndex(sourceLocation);
- color = "background:#${toColor(index)};";
+ color = "background:${toPattern(index)};";
title = sourceLocation.shortText;
currentLocation = sourceLocation;
}
@@ -151,7 +163,7 @@
for (SourceLocation sourceLocation in lastSourceLocations) {
if (sourceLocation == null) continue;
int colorIndex = collection.getIndex(sourceLocation);
- addColor('#${toColor(colorIndex)}');
+ addColor('${toColorCss(colorIndex)}');
currentLocation = sourceLocation;
}
color = 'background: linear-gradient(to right${sb}); '
@@ -363,7 +375,7 @@
codeBuffer.write(line.substring(0, start));
}
codeBuffer.write(
- '<a name="${index}" style="background:#${toColor(index)};" '
+ '<a name="${index}" style="background:${toPattern(index)};" '
'title="[${lineIndex + 1},${start + 1}]" '
'onmouseover="highlight(\'$index\');" '
'onmouseout="highlight();">');
@@ -393,14 +405,14 @@
'<th>Dart code @ mapped location</th><th>file:position:name</th></tr>');
codePoints.forEach((CodePoint codePoint) {
String jsCode = codePoint.jsCode;
- if (jsCode.length > 40) {
- jsCode = jsCode.substring(0, 40);
- }
if (codePoint.sourceLocation != null) {
int index = collection.getIndex(codePoint.sourceLocation);
if (index != null) {
-
- buffer.write('<tr style="background:#${toColor(index)};" '
+ String style = '';
+ if (!codePoint.isMissing) {
+ style = 'style="background:${toColorCss(index)};" ';
+ }
+ buffer.write('<tr $style'
'name="trace$index" '
'onmouseover="highlight([${index}]);"'
'onmouseout="highlight([]);">');
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
index 573b902..f4b0f1b 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
@@ -8,6 +8,112 @@
import 'dart:io';
+abstract class Configurations {
+ Iterable<String> get configs;
+ Iterable<String> get files;
+ String getPath(String config, String file);
+}
+
+void outputMultiConfigs(Uri uri,
+ Configurations configurations) {
+ StringBuffer sb = new StringBuffer();
+ String defaultConfig = configurations.configs.first;
+ String defaultFile = configurations.files.first;
+ sb.write('''
+<html>
+<head>
+<style>
+.button {
+ cursor: pointer;
+ padding: 10px;
+ display: inline;
+}
+iframe {
+ border: 0px;
+}
+</style>
+</head>
+<body style="margin:0px;">
+<script>
+function setAll(name, property, value) {
+ var elements = document.getElementsByName(name);
+ for (var i = 0; i < elements.length; i++) {
+ elements[i].style[property] = value;
+ }
+}
+
+var current_config;
+var current_file;
+
+function setConfig(value) {
+ var property = 'text-decoration';
+ var onValue = 'underline';
+ var offValue = 'none';
+ if (current_config != value) {
+ setAll('config:' + current_config, property, offValue);
+ setAll('src:' + current_config + ':' + current_file, 'display', 'none');
+ current_config = value;
+ setAll('config:' + current_config, property, onValue);
+ setAll('src:' + current_config + ':' + current_file, 'display', 'block');
+ }
+}
+
+function setFile(value) {
+ var property = 'text-decoration';
+ var onValue = 'underline';
+ var offValue = 'none';
+ if (current_file != value) {
+ setAll('file:' + current_file, property, offValue);
+ setAll('src:' + current_config + ':' + current_file, 'display', 'none');
+ current_file = value;
+ setAll('file:' + current_file, property, onValue);
+ setAll('src:' + current_config + ':' + current_file, 'display', 'block');
+ }
+}
+</script>
+''');
+ for (String config in configurations.configs) {
+ for (String file in configurations.files) {
+ String uri = configurations.getPath(config, file);
+ sb.write('''
+<div name="src:$config:$file"
+ style="width:100%;position:absolute;display:none;">
+ <iframe src="$uri" style="width:100%;height:100%;">
+ </iframe>
+</div>
+''');
+ }
+ }
+ sb.write('''
+<div style="right:0px;height:30px;background-color:#E0E0E0;position:fixed;">
+ file:
+''');
+ for (String file in configurations.files) {
+ sb.write('''
+ <h3 class="button" name="file:$file"
+ onclick="setFile('$file');">$file</h3>
+''');
+ }
+ sb.write('''
+ config:
+''');
+ for (String config in configurations.configs) {
+ sb.write('''
+ <h3 class="button" name="config:$config"
+ onclick="setConfig('$config');">$config</h3>
+''');
+ }
+ sb.write('''
+</div>
+<script>
+setConfig('$defaultConfig');
+setFile('$defaultFile');
+</script>
+</body>
+</html>''');
+ output(uri, sb.toString());
+}
+
/// Outputs JavaScript/Dart source mapping traces into [uri].
void outputJsDartTrace(
Uri uri,
diff --git a/tests/compiler/dart2js/trust_type_annotations2_test.dart b/tests/compiler/dart2js/trust_type_annotations2_test.dart
index 0ff5a916..cf8ad8a 100644
--- a/tests/compiler/dart2js/trust_type_annotations2_test.dart
+++ b/tests/compiler/dart2js/trust_type_annotations2_test.dart
@@ -24,11 +24,13 @@
};
main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES,
- options: ['--trust-type-annotations']);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ options: ['--trust-type-annotations']);
+ var compiler = result.compiler;
var element = compiler.mainApp.findExported('main');
var code = compiler.backend.assembleCode(element);
Expect.isTrue(code.contains('+'), code);
- }));
+ });
}
diff --git a/tests/compiler/dart2js/unneeded_part_js_test.dart b/tests/compiler/dart2js/unneeded_part_js_test.dart
index 2ad0c3e..7a13c83 100644
--- a/tests/compiler/dart2js/unneeded_part_js_test.dart
+++ b/tests/compiler/dart2js/unneeded_part_js_test.dart
@@ -5,23 +5,21 @@
// Test that no parts are emitted when deferred loading isn't used.
import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/dart2jslib.dart';
import 'package:expect/expect.dart';
import 'memory_compiler.dart';
main() {
- DiagnosticCollector diagnostics = new DiagnosticCollector();
- OutputCollector output = new OutputCollector();
- Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES,
- diagnosticHandler: diagnostics,
- outputProvider: output);
-
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ DiagnosticCollector diagnostics = new DiagnosticCollector();
+ OutputCollector output = new OutputCollector();
+ CompilationResult result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ diagnosticHandler: diagnostics,
+ outputProvider: output);
Expect.isFalse(diagnostics.hasRegularMessages);
Expect.isFalse(output.hasExtraOutput);
- Expect.isFalse(compiler.compilationFailed);
- }));
+ Expect.isTrue(result.isSuccess);
+ });
}
const Map MEMORY_SOURCE_FILES = const {
diff --git a/tests/compiler/dart2js/unused_empty_map_test.dart b/tests/compiler/dart2js/unused_empty_map_test.dart
index dfda62d..5f806bc 100644
--- a/tests/compiler/dart2js/unused_empty_map_test.dart
+++ b/tests/compiler/dart2js/unused_empty_map_test.dart
@@ -18,12 +18,12 @@
const HASHMAP_EMPTY_CONSTRUCTOR = r"LinkedHashMap_LinkedHashMap$_empty";
main() {
- var collector = new OutputCollector();
- var compiler = compilerFor(TEST_SOURCE, outputProvider: collector);
- asyncTest(() =>
- compiler.run(Uri.parse('memory:main.dart')).then((_) {
- String generated = collector.getOutput('', 'js');
- Expect.isFalse(generated.contains(HASHMAP_EMPTY_CONSTRUCTOR));
- })
- );
+ asyncTest(() async {
+ var collector = new OutputCollector();
+ var result = await runCompiler(
+ memorySourceFiles: TEST_SOURCE, outputProvider: collector);
+ var compiler = result.compiler;
+ String generated = collector.getOutput('', 'js');
+ Expect.isFalse(generated.contains(HASHMAP_EMPTY_CONSTRUCTOR));
+ });
}
diff --git a/tests/compiler/dart2js/uri_retention_test.dart b/tests/compiler/dart2js/uri_retention_test.dart
index ac9d73c..8a7a47f 100644
--- a/tests/compiler/dart2js/uri_retention_test.dart
+++ b/tests/compiler/dart2js/uri_retention_test.dart
@@ -10,18 +10,18 @@
import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart' show
- compilerFor, OutputCollector;
+ runCompiler, OutputCollector;
-Future<String> compileSources(sources, {bool minify, bool preserveUri}) {
+Future<String> compileSources(sources, {bool minify, bool preserveUri}) async {
var options = [];
if (minify) options.add("--minify");
if (preserveUri) options.add("--preserve-uris");
OutputCollector outputCollector = new OutputCollector();
- var compiler = compilerFor(
- sources, options: options, outputProvider: outputCollector);
- return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
- return outputCollector.getOutput('', 'js');
- });
+ await runCompiler(
+ memorySourceFiles: sources,
+ options: options,
+ outputProvider: outputCollector);
+ return outputCollector.getOutput('', 'js');
}
Future test(sources, { bool libName, bool fileName }) {
diff --git a/tests/compiler/dart2js/use_checks_test.dart b/tests/compiler/dart2js/use_checks_test.dart
index 67efbd0..24013ad 100644
--- a/tests/compiler/dart2js/use_checks_test.dart
+++ b/tests/compiler/dart2js/use_checks_test.dart
@@ -23,11 +23,13 @@
};
main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES,
- options: ['--enable-checked-mode']);
- asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ options: ['--enable-checked-mode']);
+ var compiler = result.compiler;
var element = compiler.mainApp.findExported('main');
var code = compiler.backend.assembleCode(element);
Expect.isTrue(code.contains('+'), code);
- }));
+ });
}
diff --git a/tests/compiler/dart2js/use_strict_test.dart b/tests/compiler/dart2js/use_strict_test.dart
index 777c77c..b99bfe0 100644
--- a/tests/compiler/dart2js/use_strict_test.dart
+++ b/tests/compiler/dart2js/use_strict_test.dart
@@ -48,8 +48,9 @@
main() {
OutputCollector collector = new OutputCollector();
- var compiler = compilerFor(MEMORY_SOURCE_FILES, outputProvider: collector);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ await runCompiler(
+ memorySourceFiles: MEMORY_SOURCE_FILES, outputProvider: collector);
String jsOutput = collector.getOutput('', 'js');
// Skip comments.
@@ -64,5 +65,5 @@
// 'arguments'.
RegExp re = new RegExp(r'[^\w$](arguments|eval)[^\w$]');
Expect.isFalse(re.hasMatch(filtered));
- }));
+ });
}
diff --git a/tests/compiler/dart2js/value_range3_test.dart b/tests/compiler/dart2js/value_range3_test.dart
index d2c95c8..5a483ed 100644
--- a/tests/compiler/dart2js/value_range3_test.dart
+++ b/tests/compiler/dart2js/value_range3_test.dart
@@ -23,11 +23,12 @@
};
main() {
- var compiler = compilerFor(MEMORY_SOURCE_FILES);
- asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ asyncTest(() async {
+ var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
+ var compiler = result.compiler;
var element = compiler.mainApp.findExported('main');
var code = compiler.backend.assembleCode(element);
Expect.isFalse(code.contains('ioore'));
- }));
+ });
}
diff --git a/tests/compiler/dart2js/warnings_checker.dart b/tests/compiler/dart2js/warnings_checker.dart
index daaa32d..cf31943 100644
--- a/tests/compiler/dart2js/warnings_checker.dart
+++ b/tests/compiler/dart2js/warnings_checker.dart
@@ -21,7 +21,7 @@
Uri script = currentDirectory.resolveUri(Platform.script);
bool warningsMismatch = false;
bool verbose = arguments != null && arguments.contains('-v');
- asyncTest(() => Future.forEach(tests.keys, (String test) {
+ asyncTest(() => Future.forEach(tests.keys, (String test) async {
Uri uri = script.resolve('../../$test');
String source = UTF8.decode(readAll(uriPathToNative(uri.path)));
SourceFile file = new StringSourceFile(
@@ -38,45 +38,44 @@
}
Set<int> unseenWarnings = new Set<int>.from(expectedWarnings.keys);
DiagnosticCollector collector = new DiagnosticCollector();
- var compiler = compilerFor(const {},
- diagnosticHandler: collector,
- options: ['--analyze-only'],
- showDiagnostics: verbose);
- return compiler.run(uri).then((_) {
- Map<String, List<int>> statusMap = tests[test];
- // Line numbers with known unexpected warnings.
- List<int> unexpectedStatus = [];
- if (statusMap != null && statusMap.containsKey('unexpected')) {
- unexpectedStatus = statusMap['unexpected'];
+ await runCompiler(
+ entryPoint: uri,
+ diagnosticHandler: collector,
+ options: ['--analyze-only'],
+ showDiagnostics: verbose);
+ Map<String, List<int>> statusMap = tests[test];
+ // Line numbers with known unexpected warnings.
+ List<int> unexpectedStatus = [];
+ if (statusMap != null && statusMap.containsKey('unexpected')) {
+ unexpectedStatus = statusMap['unexpected'];
+ }
+ // Line numbers with known missing warnings.
+ List<int> missingStatus = [];
+ if (statusMap != null && statusMap.containsKey('missing')) {
+ missingStatus = statusMap['missing'];
+ }
+ for (DiagnosticMessage message in collector.warnings) {
+ Expect.equals(uri, message.uri);
+ int lineNo = file.getLine(message.begin);
+ if (expectedWarnings.containsKey(lineNo)) {
+ unseenWarnings.remove(lineNo);
+ } else if (!unexpectedStatus.contains(lineNo+1)) {
+ warningsMismatch = true;
+ print(file.getLocationMessage(
+ 'Unexpected warning: ${message.message}',
+ message.begin, message.end));
}
- // Line numbers with known missing warnings.
- List<int> missingStatus = [];
- if (statusMap != null && statusMap.containsKey('missing')) {
- missingStatus = statusMap['missing'];
- }
- for (DiagnosticMessage message in collector.warnings) {
- Expect.equals(uri, message.uri);
- int lineNo = file.getLine(message.begin);
- if (expectedWarnings.containsKey(lineNo)) {
- unseenWarnings.remove(lineNo);
- } else if (!unexpectedStatus.contains(lineNo+1)) {
+ }
+ if (!unseenWarnings.isEmpty) {
+ for (int lineNo in unseenWarnings) {
+ if (!missingStatus.contains(lineNo+1)) {
warningsMismatch = true;
- print(file.getLocationMessage(
- 'Unexpected warning: ${message.message}',
- message.begin, message.end));
+ String line = expectedWarnings[lineNo];
+ print('$uri [${lineNo+1}]: Missing static type warning.');
+ print(line);
}
}
- if (!unseenWarnings.isEmpty) {
- for (int lineNo in unseenWarnings) {
- if (!missingStatus.contains(lineNo+1)) {
- warningsMismatch = true;
- String line = expectedWarnings[lineNo];
- print('$uri [${lineNo+1}]: Missing static type warning.');
- print(line);
- }
- }
- }
- });
+ }
}).then((_) {
Expect.isFalse(warningsMismatch);
}));
diff --git a/tests/compiler/dart2js/world_test.dart b/tests/compiler/dart2js/world_test.dart
index 436b3d7..4acd90f 100644
--- a/tests/compiler/dart2js/world_test.dart
+++ b/tests/compiler/dart2js/world_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// 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.
@@ -15,7 +15,8 @@
asyncTest(() => TypeEnvironment.create(r"""
class A {}
class B {}
- class C extends A {}
+ class C_Super extends A {}
+ class C extends C_Super {}
class D implements A {}
class E extends B implements A {}
class F extends Object with A implements B {}
@@ -63,6 +64,18 @@
}
}
+ void testSubclasses(
+ ClassElement cls,
+ List<ClassElement> expectedClasses,
+ {bool exact: true}) {
+ check(
+ 'subclassesOf',
+ cls,
+ classWorld.subclassesOf(cls),
+ expectedClasses,
+ exact: exact);
+ }
+
void testStrictSubclasses(
ClassElement cls,
List<ClassElement> expectedClasses,
@@ -99,6 +112,15 @@
exact: exact);
}
+ testSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
+ testSubclasses(A, [A, C]);
+ testSubclasses(B, [B, E]);
+ testSubclasses(C, [C]);
+ testSubclasses(D, [D]);
+ testSubclasses(E, [E]);
+ testSubclasses(F, [F]);
+ testSubclasses(G, [G]);
+
testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
testStrictSubclasses(A, [C]);
testStrictSubclasses(B, [E]);
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index e61053c..635ce98 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -85,3 +85,6 @@
mirror_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
reflect_native_types_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
switch_test/none: Crash # (switch (val){foo:ba... continue to a labeled switch case
+
+[ $compiler == none && $runtime == vm ]
+invalid_annotation_test/01: MissingCompileTimeError, OK # vm is lazy
diff --git a/tests/compiler/dart2js_extra/invalid_annotation2_test.dart b/tests/compiler/dart2js_extra/invalid_annotation2_test.dart
new file mode 100644
index 0000000..d8dafd5
--- /dev/null
+++ b/tests/compiler/dart2js_extra/invalid_annotation2_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for http://dartbug.com/23893/
+//
+// Because annotations are parsed lazily, dart2js used to crash when an
+// annotation had a syntax error.
+// This checks the same behavior as invalid_annotation_test.dart, except that we
+// use mirrors to trigger the error in the vm. This also triggers the error in
+// dart2js differently.
+
+@MirrorsUsed(targets: const [A])
+import 'dart:mirrors';
+
+@Deprecated("m"
+, /// 01: compile-time error
+)
+class A {
+}
+
+main() {
+ reflectClass(A).metadata;
+}
diff --git a/tests/compiler/dart2js_extra/invalid_annotation_test.dart b/tests/compiler/dart2js_extra/invalid_annotation_test.dart
new file mode 100644
index 0000000..5e0285a8
--- /dev/null
+++ b/tests/compiler/dart2js_extra/invalid_annotation_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for http://dartbug.com/23893/
+//
+// Because annotations are parsed lazily, dart2js used to crash when an
+// annotation had a syntax error.
+
+@Deprecated("m"
+, /// 01: compile-time error
+)
+class A {}
+
+main() => new A();
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 34e5a50..9ea2884 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -22,7 +22,7 @@
[ $compiler == dart2js && $cps_ir ]
mirror_intercepted_field_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
-native_exception_test: RuntimeError # J.getInterceptor(...).toString$0 is not a function
+native_exception_test: RuntimeError # value_.toString$0 is not a function
native_method_inlining_test: RuntimeError # Please triage this failure.
native_mirror_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
native_no_such_method_exception3_frog_test: RuntimeError # Please triage this failure.
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index acae7a0..648543c 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -214,13 +214,14 @@
[ $compiler == dart2js && $cps_ir ]
error_stack_trace1_test: Pass # H.unwrapException(...).get$stackTrace is not a function
-hashcode_test: RuntimeError # Please triage this failure.
iterable_empty_test: RuntimeError # Please triage this failure.
iterable_return_type_test/none: RuntimeError # Please triage this failure.
iterable_to_list_test: RuntimeError # Please triage this failure.
iterable_to_set_test: RuntimeError # Please triage this failure.
+list_filled_type_argument_test: RuntimeError # Please triage this failure.
list_test/01: RuntimeError # this.get$length is not a function
list_test/none: RuntimeError # this.get$length is not a function
+list_unmodifiable_test: RuntimeError # Please triage this failure.
map_values2_test: RuntimeError # Please triage this failure.
map_values3_test: RuntimeError # Please triage this failure.
map_values4_test: RuntimeError # Please triage this failure.
@@ -232,5 +233,4 @@
symbol_reserved_word_test/06: RuntimeError # Please triage this failure.
symbol_reserved_word_test/09: RuntimeError # Please triage this failure.
symbol_reserved_word_test/12: RuntimeError # Please triage this failure.
-symbol_test/none: Crash # The null object does not have a getter '_element'.
-uri_test: Crash # The null object does not have a getter '_element'.
+symbol_test/none: RuntimeError # Expected a NoSuchMethodError or a TypeError
diff --git a/tests/corelib/regexp/default_arguments_test.dart b/tests/corelib/regexp/default_arguments_test.dart
new file mode 100644
index 0000000..5b1d6e8
--- /dev/null
+++ b/tests/corelib/regexp/default_arguments_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that `null` is interpreted as `false` when passed as argument to
+// `caseSensitive` and `multiLine`.
+
+import 'package:expect/expect.dart';
+
+main() {
+ testCaseSensitive();
+ testMultiLine();
+}
+
+testCaseSensitive() {
+ var r1 = new RegExp('foo');
+ var r2 = new RegExp('foo', caseSensitive: true);
+ var r3 = new RegExp('foo', caseSensitive: false);
+ var r4 = new RegExp('foo', caseSensitive: null);
+ Expect.isNull(r1.firstMatch('Foo'), "r1.firstMatch('Foo')");
+ Expect.isNull(r2.firstMatch('Foo'), "r2.firstMatch('Foo')");
+ Expect.isNotNull(r3.firstMatch('Foo'), "r3.firstMatch('Foo')");
+ Expect.isNotNull(r4.firstMatch('Foo'), "r4.firstMatch('Foo')");
+}
+
+testMultiLine() {
+ var r1 = new RegExp(r'^foo$');
+ var r2 = new RegExp(r'^foo$', multiLine: true);
+ var r3 = new RegExp(r'^foo$', multiLine: false);
+ var r4 = new RegExp(r'^foo$', multiLine: null);
+ Expect.isNull(r1.firstMatch('\nfoo\n'), "r1.firstMatch('\\nfoo\\n')");
+ Expect.isNotNull(r2.firstMatch('\nfoo\n'), "r2.firstMatch('\\nfoo\\n')");
+ Expect.isNull(r3.firstMatch('\nfoo\n'), "r3.firstMatch('\\nfoo\\n')");
+ Expect.isNull(r4.firstMatch('\nfoo\n'), "r4.firstMatch('\\nfoo\\n')");
+}
\ No newline at end of file
diff --git a/tests/html/html.status b/tests/html/html.status
index 27ea36a..0b02629 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -106,6 +106,8 @@
[ $runtime == chrome ]
touchevent_test/supported: Fail # Touch events are only supported on touch devices
+element_animate_test/omit_timing: RuntimeError # Also timing out on MacOS. Issue 23507
+element_animate_test/timing_dict: RuntimeError # Also timing out on MacOS. Issue 23507
[ $runtime == chrome && $system == macos ]
element_animate_test/omit_timing: Skip # Timing out on MacOS. Issue 23507
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index a683b66..41355d7 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -58,9 +58,14 @@
message3_test/constInstance: RuntimeError # Issue 21817
browser/issue_12474_test: CompileTimeError # Issue 22529
enum_const_test/02: RuntimeError # Issue 21817
-error_exit_at_spawn_test: Fail, Timeout # Issue 23876
-error_at_spawn_test: Fail, Timeout # Issue 23876
-exit_at_spawn_test: Fail, Timeout # Issue 23876
+error_exit_at_spawn_test: Fail # Issue 23876
+error_at_spawn_test: Fail # Issue 23876
+exit_at_spawn_test: Fail # Issue 23876
+
+[ $compiler == dart2js && $runtime != d8 ]
+error_exit_at_spawn_test: Skip # Issue 23876
+error_at_spawn_test: Skip # Issue 23876
+exit_at_spawn_test: Skip # Issue 23876
[ $compiler == dart2js && $jscl ]
spawn_uri_test: SkipByDesign # Loading another file is not supported in JS shell
diff --git a/tests/language/bool_condition_check_test.dart b/tests/language/bool_condition_check_test.dart
new file mode 100644
index 0000000..facab4b
--- /dev/null
+++ b/tests/language/bool_condition_check_test.dart
@@ -0,0 +1,24 @@
+// 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.
+
+// Check that passing `null` for a boolean typed parameter will still cause
+// a boolean conversion error when used in a condition in checked mode.
+
+import 'package:expect/expect.dart';
+
+@NoInline()
+String check({bool a, bool b}) {
+ String a_string = a ? 'a' : '';
+ String b_string = b ? 'b' : '';
+ return '$a_string$b_string';
+}
+
+class Class {
+ final String field;
+ Class({bool a: false, bool b: true}) : this.field = check(a: a, b: b);
+}
+
+main() {
+ Expect.equals('', new Class(a: null, b: null).field); /// 01: dynamic type error
+}
\ No newline at end of file
diff --git a/tests/language/call_function_apply_test.dart b/tests/language/call_function_apply_test.dart
new file mode 100644
index 0000000..935cfaf
--- /dev/null
+++ b/tests/language/call_function_apply_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ call({a: 42}) {
+ return 499 + a;
+ }
+}
+
+main() {
+ Expect.equals(497, Function.apply(new A(), [], {#a: -2}));
+}
diff --git a/tests/language/classes_static_method_clash_test.dart b/tests/language/classes_static_method_clash_test.dart
new file mode 100644
index 0000000..0822897
--- /dev/null
+++ b/tests/language/classes_static_method_clash_test.dart
@@ -0,0 +1,5464 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// This methods needs a stub method (because it is used in Function.apply, where
+// we can't see all possible uses).
+// The stub-method(s) must not clash with other global names (like classes).
+foo({a:499}) => a;
+
+bar(f) {
+ return f();
+ return null;
+}
+
+int confuse(x) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) confuse(x + 1);
+ return x;
+}
+
+main() {
+ Expect.equals(42, Function.apply(foo, [], {#a: 42}));
+ Expect.equals(499, Function.apply(foo, [], null));
+ print(objects[confuse(0)]);
+}
+
+/*
+The following code has been generated with the following script:
+
+get chars sync* {
+ for (int i = "a".codeUnitAt(0); i <= "z".codeUnitAt(0); i++) {
+ yield new String.fromCharCodes([i]);
+ }
+ for (int i = "A".codeUnitAt(0); i <= "Z".codeUnitAt(0); i++) {
+ yield new String.fromCharCodes([i]);
+ }
+}
+
+main() {
+ StringBuffer classes = new StringBuffer();
+ print("var objects = [");
+ for (String c1 in chars) {
+ for (String c2 in chars) {
+ print(" new C$c1$c2(),");
+ classes.writeln("class C$c1$c2{}");
+ }
+ }
+ print("];");
+ print(classes.toString());
+}
+*/
+
+var objects = [
+ new Caa(),
+ new Cab(),
+ new Cac(),
+ new Cad(),
+ new Cae(),
+ new Caf(),
+ new Cag(),
+ new Cah(),
+ new Cai(),
+ new Caj(),
+ new Cak(),
+ new Cal(),
+ new Cam(),
+ new Can(),
+ new Cao(),
+ new Cap(),
+ new Caq(),
+ new Car(),
+ new Cas(),
+ new Cat(),
+ new Cau(),
+ new Cav(),
+ new Caw(),
+ new Cax(),
+ new Cay(),
+ new Caz(),
+ new CaA(),
+ new CaB(),
+ new CaC(),
+ new CaD(),
+ new CaE(),
+ new CaF(),
+ new CaG(),
+ new CaH(),
+ new CaI(),
+ new CaJ(),
+ new CaK(),
+ new CaL(),
+ new CaM(),
+ new CaN(),
+ new CaO(),
+ new CaP(),
+ new CaQ(),
+ new CaR(),
+ new CaS(),
+ new CaT(),
+ new CaU(),
+ new CaV(),
+ new CaW(),
+ new CaX(),
+ new CaY(),
+ new CaZ(),
+ new Cba(),
+ new Cbb(),
+ new Cbc(),
+ new Cbd(),
+ new Cbe(),
+ new Cbf(),
+ new Cbg(),
+ new Cbh(),
+ new Cbi(),
+ new Cbj(),
+ new Cbk(),
+ new Cbl(),
+ new Cbm(),
+ new Cbn(),
+ new Cbo(),
+ new Cbp(),
+ new Cbq(),
+ new Cbr(),
+ new Cbs(),
+ new Cbt(),
+ new Cbu(),
+ new Cbv(),
+ new Cbw(),
+ new Cbx(),
+ new Cby(),
+ new Cbz(),
+ new CbA(),
+ new CbB(),
+ new CbC(),
+ new CbD(),
+ new CbE(),
+ new CbF(),
+ new CbG(),
+ new CbH(),
+ new CbI(),
+ new CbJ(),
+ new CbK(),
+ new CbL(),
+ new CbM(),
+ new CbN(),
+ new CbO(),
+ new CbP(),
+ new CbQ(),
+ new CbR(),
+ new CbS(),
+ new CbT(),
+ new CbU(),
+ new CbV(),
+ new CbW(),
+ new CbX(),
+ new CbY(),
+ new CbZ(),
+ new Cca(),
+ new Ccb(),
+ new Ccc(),
+ new Ccd(),
+ new Cce(),
+ new Ccf(),
+ new Ccg(),
+ new Cch(),
+ new Cci(),
+ new Ccj(),
+ new Cck(),
+ new Ccl(),
+ new Ccm(),
+ new Ccn(),
+ new Cco(),
+ new Ccp(),
+ new Ccq(),
+ new Ccr(),
+ new Ccs(),
+ new Cct(),
+ new Ccu(),
+ new Ccv(),
+ new Ccw(),
+ new Ccx(),
+ new Ccy(),
+ new Ccz(),
+ new CcA(),
+ new CcB(),
+ new CcC(),
+ new CcD(),
+ new CcE(),
+ new CcF(),
+ new CcG(),
+ new CcH(),
+ new CcI(),
+ new CcJ(),
+ new CcK(),
+ new CcL(),
+ new CcM(),
+ new CcN(),
+ new CcO(),
+ new CcP(),
+ new CcQ(),
+ new CcR(),
+ new CcS(),
+ new CcT(),
+ new CcU(),
+ new CcV(),
+ new CcW(),
+ new CcX(),
+ new CcY(),
+ new CcZ(),
+ new Cda(),
+ new Cdb(),
+ new Cdc(),
+ new Cdd(),
+ new Cde(),
+ new Cdf(),
+ new Cdg(),
+ new Cdh(),
+ new Cdi(),
+ new Cdj(),
+ new Cdk(),
+ new Cdl(),
+ new Cdm(),
+ new Cdn(),
+ new Cdo(),
+ new Cdp(),
+ new Cdq(),
+ new Cdr(),
+ new Cds(),
+ new Cdt(),
+ new Cdu(),
+ new Cdv(),
+ new Cdw(),
+ new Cdx(),
+ new Cdy(),
+ new Cdz(),
+ new CdA(),
+ new CdB(),
+ new CdC(),
+ new CdD(),
+ new CdE(),
+ new CdF(),
+ new CdG(),
+ new CdH(),
+ new CdI(),
+ new CdJ(),
+ new CdK(),
+ new CdL(),
+ new CdM(),
+ new CdN(),
+ new CdO(),
+ new CdP(),
+ new CdQ(),
+ new CdR(),
+ new CdS(),
+ new CdT(),
+ new CdU(),
+ new CdV(),
+ new CdW(),
+ new CdX(),
+ new CdY(),
+ new CdZ(),
+ new Cea(),
+ new Ceb(),
+ new Cec(),
+ new Ced(),
+ new Cee(),
+ new Cef(),
+ new Ceg(),
+ new Ceh(),
+ new Cei(),
+ new Cej(),
+ new Cek(),
+ new Cel(),
+ new Cem(),
+ new Cen(),
+ new Ceo(),
+ new Cep(),
+ new Ceq(),
+ new Cer(),
+ new Ces(),
+ new Cet(),
+ new Ceu(),
+ new Cev(),
+ new Cew(),
+ new Cex(),
+ new Cey(),
+ new Cez(),
+ new CeA(),
+ new CeB(),
+ new CeC(),
+ new CeD(),
+ new CeE(),
+ new CeF(),
+ new CeG(),
+ new CeH(),
+ new CeI(),
+ new CeJ(),
+ new CeK(),
+ new CeL(),
+ new CeM(),
+ new CeN(),
+ new CeO(),
+ new CeP(),
+ new CeQ(),
+ new CeR(),
+ new CeS(),
+ new CeT(),
+ new CeU(),
+ new CeV(),
+ new CeW(),
+ new CeX(),
+ new CeY(),
+ new CeZ(),
+ new Cfa(),
+ new Cfb(),
+ new Cfc(),
+ new Cfd(),
+ new Cfe(),
+ new Cff(),
+ new Cfg(),
+ new Cfh(),
+ new Cfi(),
+ new Cfj(),
+ new Cfk(),
+ new Cfl(),
+ new Cfm(),
+ new Cfn(),
+ new Cfo(),
+ new Cfp(),
+ new Cfq(),
+ new Cfr(),
+ new Cfs(),
+ new Cft(),
+ new Cfu(),
+ new Cfv(),
+ new Cfw(),
+ new Cfx(),
+ new Cfy(),
+ new Cfz(),
+ new CfA(),
+ new CfB(),
+ new CfC(),
+ new CfD(),
+ new CfE(),
+ new CfF(),
+ new CfG(),
+ new CfH(),
+ new CfI(),
+ new CfJ(),
+ new CfK(),
+ new CfL(),
+ new CfM(),
+ new CfN(),
+ new CfO(),
+ new CfP(),
+ new CfQ(),
+ new CfR(),
+ new CfS(),
+ new CfT(),
+ new CfU(),
+ new CfV(),
+ new CfW(),
+ new CfX(),
+ new CfY(),
+ new CfZ(),
+ new Cga(),
+ new Cgb(),
+ new Cgc(),
+ new Cgd(),
+ new Cge(),
+ new Cgf(),
+ new Cgg(),
+ new Cgh(),
+ new Cgi(),
+ new Cgj(),
+ new Cgk(),
+ new Cgl(),
+ new Cgm(),
+ new Cgn(),
+ new Cgo(),
+ new Cgp(),
+ new Cgq(),
+ new Cgr(),
+ new Cgs(),
+ new Cgt(),
+ new Cgu(),
+ new Cgv(),
+ new Cgw(),
+ new Cgx(),
+ new Cgy(),
+ new Cgz(),
+ new CgA(),
+ new CgB(),
+ new CgC(),
+ new CgD(),
+ new CgE(),
+ new CgF(),
+ new CgG(),
+ new CgH(),
+ new CgI(),
+ new CgJ(),
+ new CgK(),
+ new CgL(),
+ new CgM(),
+ new CgN(),
+ new CgO(),
+ new CgP(),
+ new CgQ(),
+ new CgR(),
+ new CgS(),
+ new CgT(),
+ new CgU(),
+ new CgV(),
+ new CgW(),
+ new CgX(),
+ new CgY(),
+ new CgZ(),
+ new Cha(),
+ new Chb(),
+ new Chc(),
+ new Chd(),
+ new Che(),
+ new Chf(),
+ new Chg(),
+ new Chh(),
+ new Chi(),
+ new Chj(),
+ new Chk(),
+ new Chl(),
+ new Chm(),
+ new Chn(),
+ new Cho(),
+ new Chp(),
+ new Chq(),
+ new Chr(),
+ new Chs(),
+ new Cht(),
+ new Chu(),
+ new Chv(),
+ new Chw(),
+ new Chx(),
+ new Chy(),
+ new Chz(),
+ new ChA(),
+ new ChB(),
+ new ChC(),
+ new ChD(),
+ new ChE(),
+ new ChF(),
+ new ChG(),
+ new ChH(),
+ new ChI(),
+ new ChJ(),
+ new ChK(),
+ new ChL(),
+ new ChM(),
+ new ChN(),
+ new ChO(),
+ new ChP(),
+ new ChQ(),
+ new ChR(),
+ new ChS(),
+ new ChT(),
+ new ChU(),
+ new ChV(),
+ new ChW(),
+ new ChX(),
+ new ChY(),
+ new ChZ(),
+ new Cia(),
+ new Cib(),
+ new Cic(),
+ new Cid(),
+ new Cie(),
+ new Cif(),
+ new Cig(),
+ new Cih(),
+ new Cii(),
+ new Cij(),
+ new Cik(),
+ new Cil(),
+ new Cim(),
+ new Cin(),
+ new Cio(),
+ new Cip(),
+ new Ciq(),
+ new Cir(),
+ new Cis(),
+ new Cit(),
+ new Ciu(),
+ new Civ(),
+ new Ciw(),
+ new Cix(),
+ new Ciy(),
+ new Ciz(),
+ new CiA(),
+ new CiB(),
+ new CiC(),
+ new CiD(),
+ new CiE(),
+ new CiF(),
+ new CiG(),
+ new CiH(),
+ new CiI(),
+ new CiJ(),
+ new CiK(),
+ new CiL(),
+ new CiM(),
+ new CiN(),
+ new CiO(),
+ new CiP(),
+ new CiQ(),
+ new CiR(),
+ new CiS(),
+ new CiT(),
+ new CiU(),
+ new CiV(),
+ new CiW(),
+ new CiX(),
+ new CiY(),
+ new CiZ(),
+ new Cja(),
+ new Cjb(),
+ new Cjc(),
+ new Cjd(),
+ new Cje(),
+ new Cjf(),
+ new Cjg(),
+ new Cjh(),
+ new Cji(),
+ new Cjj(),
+ new Cjk(),
+ new Cjl(),
+ new Cjm(),
+ new Cjn(),
+ new Cjo(),
+ new Cjp(),
+ new Cjq(),
+ new Cjr(),
+ new Cjs(),
+ new Cjt(),
+ new Cju(),
+ new Cjv(),
+ new Cjw(),
+ new Cjx(),
+ new Cjy(),
+ new Cjz(),
+ new CjA(),
+ new CjB(),
+ new CjC(),
+ new CjD(),
+ new CjE(),
+ new CjF(),
+ new CjG(),
+ new CjH(),
+ new CjI(),
+ new CjJ(),
+ new CjK(),
+ new CjL(),
+ new CjM(),
+ new CjN(),
+ new CjO(),
+ new CjP(),
+ new CjQ(),
+ new CjR(),
+ new CjS(),
+ new CjT(),
+ new CjU(),
+ new CjV(),
+ new CjW(),
+ new CjX(),
+ new CjY(),
+ new CjZ(),
+ new Cka(),
+ new Ckb(),
+ new Ckc(),
+ new Ckd(),
+ new Cke(),
+ new Ckf(),
+ new Ckg(),
+ new Ckh(),
+ new Cki(),
+ new Ckj(),
+ new Ckk(),
+ new Ckl(),
+ new Ckm(),
+ new Ckn(),
+ new Cko(),
+ new Ckp(),
+ new Ckq(),
+ new Ckr(),
+ new Cks(),
+ new Ckt(),
+ new Cku(),
+ new Ckv(),
+ new Ckw(),
+ new Ckx(),
+ new Cky(),
+ new Ckz(),
+ new CkA(),
+ new CkB(),
+ new CkC(),
+ new CkD(),
+ new CkE(),
+ new CkF(),
+ new CkG(),
+ new CkH(),
+ new CkI(),
+ new CkJ(),
+ new CkK(),
+ new CkL(),
+ new CkM(),
+ new CkN(),
+ new CkO(),
+ new CkP(),
+ new CkQ(),
+ new CkR(),
+ new CkS(),
+ new CkT(),
+ new CkU(),
+ new CkV(),
+ new CkW(),
+ new CkX(),
+ new CkY(),
+ new CkZ(),
+ new Cla(),
+ new Clb(),
+ new Clc(),
+ new Cld(),
+ new Cle(),
+ new Clf(),
+ new Clg(),
+ new Clh(),
+ new Cli(),
+ new Clj(),
+ new Clk(),
+ new Cll(),
+ new Clm(),
+ new Cln(),
+ new Clo(),
+ new Clp(),
+ new Clq(),
+ new Clr(),
+ new Cls(),
+ new Clt(),
+ new Clu(),
+ new Clv(),
+ new Clw(),
+ new Clx(),
+ new Cly(),
+ new Clz(),
+ new ClA(),
+ new ClB(),
+ new ClC(),
+ new ClD(),
+ new ClE(),
+ new ClF(),
+ new ClG(),
+ new ClH(),
+ new ClI(),
+ new ClJ(),
+ new ClK(),
+ new ClL(),
+ new ClM(),
+ new ClN(),
+ new ClO(),
+ new ClP(),
+ new ClQ(),
+ new ClR(),
+ new ClS(),
+ new ClT(),
+ new ClU(),
+ new ClV(),
+ new ClW(),
+ new ClX(),
+ new ClY(),
+ new ClZ(),
+ new Cma(),
+ new Cmb(),
+ new Cmc(),
+ new Cmd(),
+ new Cme(),
+ new Cmf(),
+ new Cmg(),
+ new Cmh(),
+ new Cmi(),
+ new Cmj(),
+ new Cmk(),
+ new Cml(),
+ new Cmm(),
+ new Cmn(),
+ new Cmo(),
+ new Cmp(),
+ new Cmq(),
+ new Cmr(),
+ new Cms(),
+ new Cmt(),
+ new Cmu(),
+ new Cmv(),
+ new Cmw(),
+ new Cmx(),
+ new Cmy(),
+ new Cmz(),
+ new CmA(),
+ new CmB(),
+ new CmC(),
+ new CmD(),
+ new CmE(),
+ new CmF(),
+ new CmG(),
+ new CmH(),
+ new CmI(),
+ new CmJ(),
+ new CmK(),
+ new CmL(),
+ new CmM(),
+ new CmN(),
+ new CmO(),
+ new CmP(),
+ new CmQ(),
+ new CmR(),
+ new CmS(),
+ new CmT(),
+ new CmU(),
+ new CmV(),
+ new CmW(),
+ new CmX(),
+ new CmY(),
+ new CmZ(),
+ new Cna(),
+ new Cnb(),
+ new Cnc(),
+ new Cnd(),
+ new Cne(),
+ new Cnf(),
+ new Cng(),
+ new Cnh(),
+ new Cni(),
+ new Cnj(),
+ new Cnk(),
+ new Cnl(),
+ new Cnm(),
+ new Cnn(),
+ new Cno(),
+ new Cnp(),
+ new Cnq(),
+ new Cnr(),
+ new Cns(),
+ new Cnt(),
+ new Cnu(),
+ new Cnv(),
+ new Cnw(),
+ new Cnx(),
+ new Cny(),
+ new Cnz(),
+ new CnA(),
+ new CnB(),
+ new CnC(),
+ new CnD(),
+ new CnE(),
+ new CnF(),
+ new CnG(),
+ new CnH(),
+ new CnI(),
+ new CnJ(),
+ new CnK(),
+ new CnL(),
+ new CnM(),
+ new CnN(),
+ new CnO(),
+ new CnP(),
+ new CnQ(),
+ new CnR(),
+ new CnS(),
+ new CnT(),
+ new CnU(),
+ new CnV(),
+ new CnW(),
+ new CnX(),
+ new CnY(),
+ new CnZ(),
+ new Coa(),
+ new Cob(),
+ new Coc(),
+ new Cod(),
+ new Coe(),
+ new Cof(),
+ new Cog(),
+ new Coh(),
+ new Coi(),
+ new Coj(),
+ new Cok(),
+ new Col(),
+ new Com(),
+ new Con(),
+ new Coo(),
+ new Cop(),
+ new Coq(),
+ new Cor(),
+ new Cos(),
+ new Cot(),
+ new Cou(),
+ new Cov(),
+ new Cow(),
+ new Cox(),
+ new Coy(),
+ new Coz(),
+ new CoA(),
+ new CoB(),
+ new CoC(),
+ new CoD(),
+ new CoE(),
+ new CoF(),
+ new CoG(),
+ new CoH(),
+ new CoI(),
+ new CoJ(),
+ new CoK(),
+ new CoL(),
+ new CoM(),
+ new CoN(),
+ new CoO(),
+ new CoP(),
+ new CoQ(),
+ new CoR(),
+ new CoS(),
+ new CoT(),
+ new CoU(),
+ new CoV(),
+ new CoW(),
+ new CoX(),
+ new CoY(),
+ new CoZ(),
+ new Cpa(),
+ new Cpb(),
+ new Cpc(),
+ new Cpd(),
+ new Cpe(),
+ new Cpf(),
+ new Cpg(),
+ new Cph(),
+ new Cpi(),
+ new Cpj(),
+ new Cpk(),
+ new Cpl(),
+ new Cpm(),
+ new Cpn(),
+ new Cpo(),
+ new Cpp(),
+ new Cpq(),
+ new Cpr(),
+ new Cps(),
+ new Cpt(),
+ new Cpu(),
+ new Cpv(),
+ new Cpw(),
+ new Cpx(),
+ new Cpy(),
+ new Cpz(),
+ new CpA(),
+ new CpB(),
+ new CpC(),
+ new CpD(),
+ new CpE(),
+ new CpF(),
+ new CpG(),
+ new CpH(),
+ new CpI(),
+ new CpJ(),
+ new CpK(),
+ new CpL(),
+ new CpM(),
+ new CpN(),
+ new CpO(),
+ new CpP(),
+ new CpQ(),
+ new CpR(),
+ new CpS(),
+ new CpT(),
+ new CpU(),
+ new CpV(),
+ new CpW(),
+ new CpX(),
+ new CpY(),
+ new CpZ(),
+ new Cqa(),
+ new Cqb(),
+ new Cqc(),
+ new Cqd(),
+ new Cqe(),
+ new Cqf(),
+ new Cqg(),
+ new Cqh(),
+ new Cqi(),
+ new Cqj(),
+ new Cqk(),
+ new Cql(),
+ new Cqm(),
+ new Cqn(),
+ new Cqo(),
+ new Cqp(),
+ new Cqq(),
+ new Cqr(),
+ new Cqs(),
+ new Cqt(),
+ new Cqu(),
+ new Cqv(),
+ new Cqw(),
+ new Cqx(),
+ new Cqy(),
+ new Cqz(),
+ new CqA(),
+ new CqB(),
+ new CqC(),
+ new CqD(),
+ new CqE(),
+ new CqF(),
+ new CqG(),
+ new CqH(),
+ new CqI(),
+ new CqJ(),
+ new CqK(),
+ new CqL(),
+ new CqM(),
+ new CqN(),
+ new CqO(),
+ new CqP(),
+ new CqQ(),
+ new CqR(),
+ new CqS(),
+ new CqT(),
+ new CqU(),
+ new CqV(),
+ new CqW(),
+ new CqX(),
+ new CqY(),
+ new CqZ(),
+ new Cra(),
+ new Crb(),
+ new Crc(),
+ new Crd(),
+ new Cre(),
+ new Crf(),
+ new Crg(),
+ new Crh(),
+ new Cri(),
+ new Crj(),
+ new Crk(),
+ new Crl(),
+ new Crm(),
+ new Crn(),
+ new Cro(),
+ new Crp(),
+ new Crq(),
+ new Crr(),
+ new Crs(),
+ new Crt(),
+ new Cru(),
+ new Crv(),
+ new Crw(),
+ new Crx(),
+ new Cry(),
+ new Crz(),
+ new CrA(),
+ new CrB(),
+ new CrC(),
+ new CrD(),
+ new CrE(),
+ new CrF(),
+ new CrG(),
+ new CrH(),
+ new CrI(),
+ new CrJ(),
+ new CrK(),
+ new CrL(),
+ new CrM(),
+ new CrN(),
+ new CrO(),
+ new CrP(),
+ new CrQ(),
+ new CrR(),
+ new CrS(),
+ new CrT(),
+ new CrU(),
+ new CrV(),
+ new CrW(),
+ new CrX(),
+ new CrY(),
+ new CrZ(),
+ new Csa(),
+ new Csb(),
+ new Csc(),
+ new Csd(),
+ new Cse(),
+ new Csf(),
+ new Csg(),
+ new Csh(),
+ new Csi(),
+ new Csj(),
+ new Csk(),
+ new Csl(),
+ new Csm(),
+ new Csn(),
+ new Cso(),
+ new Csp(),
+ new Csq(),
+ new Csr(),
+ new Css(),
+ new Cst(),
+ new Csu(),
+ new Csv(),
+ new Csw(),
+ new Csx(),
+ new Csy(),
+ new Csz(),
+ new CsA(),
+ new CsB(),
+ new CsC(),
+ new CsD(),
+ new CsE(),
+ new CsF(),
+ new CsG(),
+ new CsH(),
+ new CsI(),
+ new CsJ(),
+ new CsK(),
+ new CsL(),
+ new CsM(),
+ new CsN(),
+ new CsO(),
+ new CsP(),
+ new CsQ(),
+ new CsR(),
+ new CsS(),
+ new CsT(),
+ new CsU(),
+ new CsV(),
+ new CsW(),
+ new CsX(),
+ new CsY(),
+ new CsZ(),
+ new Cta(),
+ new Ctb(),
+ new Ctc(),
+ new Ctd(),
+ new Cte(),
+ new Ctf(),
+ new Ctg(),
+ new Cth(),
+ new Cti(),
+ new Ctj(),
+ new Ctk(),
+ new Ctl(),
+ new Ctm(),
+ new Ctn(),
+ new Cto(),
+ new Ctp(),
+ new Ctq(),
+ new Ctr(),
+ new Cts(),
+ new Ctt(),
+ new Ctu(),
+ new Ctv(),
+ new Ctw(),
+ new Ctx(),
+ new Cty(),
+ new Ctz(),
+ new CtA(),
+ new CtB(),
+ new CtC(),
+ new CtD(),
+ new CtE(),
+ new CtF(),
+ new CtG(),
+ new CtH(),
+ new CtI(),
+ new CtJ(),
+ new CtK(),
+ new CtL(),
+ new CtM(),
+ new CtN(),
+ new CtO(),
+ new CtP(),
+ new CtQ(),
+ new CtR(),
+ new CtS(),
+ new CtT(),
+ new CtU(),
+ new CtV(),
+ new CtW(),
+ new CtX(),
+ new CtY(),
+ new CtZ(),
+ new Cua(),
+ new Cub(),
+ new Cuc(),
+ new Cud(),
+ new Cue(),
+ new Cuf(),
+ new Cug(),
+ new Cuh(),
+ new Cui(),
+ new Cuj(),
+ new Cuk(),
+ new Cul(),
+ new Cum(),
+ new Cun(),
+ new Cuo(),
+ new Cup(),
+ new Cuq(),
+ new Cur(),
+ new Cus(),
+ new Cut(),
+ new Cuu(),
+ new Cuv(),
+ new Cuw(),
+ new Cux(),
+ new Cuy(),
+ new Cuz(),
+ new CuA(),
+ new CuB(),
+ new CuC(),
+ new CuD(),
+ new CuE(),
+ new CuF(),
+ new CuG(),
+ new CuH(),
+ new CuI(),
+ new CuJ(),
+ new CuK(),
+ new CuL(),
+ new CuM(),
+ new CuN(),
+ new CuO(),
+ new CuP(),
+ new CuQ(),
+ new CuR(),
+ new CuS(),
+ new CuT(),
+ new CuU(),
+ new CuV(),
+ new CuW(),
+ new CuX(),
+ new CuY(),
+ new CuZ(),
+ new Cva(),
+ new Cvb(),
+ new Cvc(),
+ new Cvd(),
+ new Cve(),
+ new Cvf(),
+ new Cvg(),
+ new Cvh(),
+ new Cvi(),
+ new Cvj(),
+ new Cvk(),
+ new Cvl(),
+ new Cvm(),
+ new Cvn(),
+ new Cvo(),
+ new Cvp(),
+ new Cvq(),
+ new Cvr(),
+ new Cvs(),
+ new Cvt(),
+ new Cvu(),
+ new Cvv(),
+ new Cvw(),
+ new Cvx(),
+ new Cvy(),
+ new Cvz(),
+ new CvA(),
+ new CvB(),
+ new CvC(),
+ new CvD(),
+ new CvE(),
+ new CvF(),
+ new CvG(),
+ new CvH(),
+ new CvI(),
+ new CvJ(),
+ new CvK(),
+ new CvL(),
+ new CvM(),
+ new CvN(),
+ new CvO(),
+ new CvP(),
+ new CvQ(),
+ new CvR(),
+ new CvS(),
+ new CvT(),
+ new CvU(),
+ new CvV(),
+ new CvW(),
+ new CvX(),
+ new CvY(),
+ new CvZ(),
+ new Cwa(),
+ new Cwb(),
+ new Cwc(),
+ new Cwd(),
+ new Cwe(),
+ new Cwf(),
+ new Cwg(),
+ new Cwh(),
+ new Cwi(),
+ new Cwj(),
+ new Cwk(),
+ new Cwl(),
+ new Cwm(),
+ new Cwn(),
+ new Cwo(),
+ new Cwp(),
+ new Cwq(),
+ new Cwr(),
+ new Cws(),
+ new Cwt(),
+ new Cwu(),
+ new Cwv(),
+ new Cww(),
+ new Cwx(),
+ new Cwy(),
+ new Cwz(),
+ new CwA(),
+ new CwB(),
+ new CwC(),
+ new CwD(),
+ new CwE(),
+ new CwF(),
+ new CwG(),
+ new CwH(),
+ new CwI(),
+ new CwJ(),
+ new CwK(),
+ new CwL(),
+ new CwM(),
+ new CwN(),
+ new CwO(),
+ new CwP(),
+ new CwQ(),
+ new CwR(),
+ new CwS(),
+ new CwT(),
+ new CwU(),
+ new CwV(),
+ new CwW(),
+ new CwX(),
+ new CwY(),
+ new CwZ(),
+ new Cxa(),
+ new Cxb(),
+ new Cxc(),
+ new Cxd(),
+ new Cxe(),
+ new Cxf(),
+ new Cxg(),
+ new Cxh(),
+ new Cxi(),
+ new Cxj(),
+ new Cxk(),
+ new Cxl(),
+ new Cxm(),
+ new Cxn(),
+ new Cxo(),
+ new Cxp(),
+ new Cxq(),
+ new Cxr(),
+ new Cxs(),
+ new Cxt(),
+ new Cxu(),
+ new Cxv(),
+ new Cxw(),
+ new Cxx(),
+ new Cxy(),
+ new Cxz(),
+ new CxA(),
+ new CxB(),
+ new CxC(),
+ new CxD(),
+ new CxE(),
+ new CxF(),
+ new CxG(),
+ new CxH(),
+ new CxI(),
+ new CxJ(),
+ new CxK(),
+ new CxL(),
+ new CxM(),
+ new CxN(),
+ new CxO(),
+ new CxP(),
+ new CxQ(),
+ new CxR(),
+ new CxS(),
+ new CxT(),
+ new CxU(),
+ new CxV(),
+ new CxW(),
+ new CxX(),
+ new CxY(),
+ new CxZ(),
+ new Cya(),
+ new Cyb(),
+ new Cyc(),
+ new Cyd(),
+ new Cye(),
+ new Cyf(),
+ new Cyg(),
+ new Cyh(),
+ new Cyi(),
+ new Cyj(),
+ new Cyk(),
+ new Cyl(),
+ new Cym(),
+ new Cyn(),
+ new Cyo(),
+ new Cyp(),
+ new Cyq(),
+ new Cyr(),
+ new Cys(),
+ new Cyt(),
+ new Cyu(),
+ new Cyv(),
+ new Cyw(),
+ new Cyx(),
+ new Cyy(),
+ new Cyz(),
+ new CyA(),
+ new CyB(),
+ new CyC(),
+ new CyD(),
+ new CyE(),
+ new CyF(),
+ new CyG(),
+ new CyH(),
+ new CyI(),
+ new CyJ(),
+ new CyK(),
+ new CyL(),
+ new CyM(),
+ new CyN(),
+ new CyO(),
+ new CyP(),
+ new CyQ(),
+ new CyR(),
+ new CyS(),
+ new CyT(),
+ new CyU(),
+ new CyV(),
+ new CyW(),
+ new CyX(),
+ new CyY(),
+ new CyZ(),
+ new Cza(),
+ new Czb(),
+ new Czc(),
+ new Czd(),
+ new Cze(),
+ new Czf(),
+ new Czg(),
+ new Czh(),
+ new Czi(),
+ new Czj(),
+ new Czk(),
+ new Czl(),
+ new Czm(),
+ new Czn(),
+ new Czo(),
+ new Czp(),
+ new Czq(),
+ new Czr(),
+ new Czs(),
+ new Czt(),
+ new Czu(),
+ new Czv(),
+ new Czw(),
+ new Czx(),
+ new Czy(),
+ new Czz(),
+ new CzA(),
+ new CzB(),
+ new CzC(),
+ new CzD(),
+ new CzE(),
+ new CzF(),
+ new CzG(),
+ new CzH(),
+ new CzI(),
+ new CzJ(),
+ new CzK(),
+ new CzL(),
+ new CzM(),
+ new CzN(),
+ new CzO(),
+ new CzP(),
+ new CzQ(),
+ new CzR(),
+ new CzS(),
+ new CzT(),
+ new CzU(),
+ new CzV(),
+ new CzW(),
+ new CzX(),
+ new CzY(),
+ new CzZ(),
+ new CAa(),
+ new CAb(),
+ new CAc(),
+ new CAd(),
+ new CAe(),
+ new CAf(),
+ new CAg(),
+ new CAh(),
+ new CAi(),
+ new CAj(),
+ new CAk(),
+ new CAl(),
+ new CAm(),
+ new CAn(),
+ new CAo(),
+ new CAp(),
+ new CAq(),
+ new CAr(),
+ new CAs(),
+ new CAt(),
+ new CAu(),
+ new CAv(),
+ new CAw(),
+ new CAx(),
+ new CAy(),
+ new CAz(),
+ new CAA(),
+ new CAB(),
+ new CAC(),
+ new CAD(),
+ new CAE(),
+ new CAF(),
+ new CAG(),
+ new CAH(),
+ new CAI(),
+ new CAJ(),
+ new CAK(),
+ new CAL(),
+ new CAM(),
+ new CAN(),
+ new CAO(),
+ new CAP(),
+ new CAQ(),
+ new CAR(),
+ new CAS(),
+ new CAT(),
+ new CAU(),
+ new CAV(),
+ new CAW(),
+ new CAX(),
+ new CAY(),
+ new CAZ(),
+ new CBa(),
+ new CBb(),
+ new CBc(),
+ new CBd(),
+ new CBe(),
+ new CBf(),
+ new CBg(),
+ new CBh(),
+ new CBi(),
+ new CBj(),
+ new CBk(),
+ new CBl(),
+ new CBm(),
+ new CBn(),
+ new CBo(),
+ new CBp(),
+ new CBq(),
+ new CBr(),
+ new CBs(),
+ new CBt(),
+ new CBu(),
+ new CBv(),
+ new CBw(),
+ new CBx(),
+ new CBy(),
+ new CBz(),
+ new CBA(),
+ new CBB(),
+ new CBC(),
+ new CBD(),
+ new CBE(),
+ new CBF(),
+ new CBG(),
+ new CBH(),
+ new CBI(),
+ new CBJ(),
+ new CBK(),
+ new CBL(),
+ new CBM(),
+ new CBN(),
+ new CBO(),
+ new CBP(),
+ new CBQ(),
+ new CBR(),
+ new CBS(),
+ new CBT(),
+ new CBU(),
+ new CBV(),
+ new CBW(),
+ new CBX(),
+ new CBY(),
+ new CBZ(),
+ new CCa(),
+ new CCb(),
+ new CCc(),
+ new CCd(),
+ new CCe(),
+ new CCf(),
+ new CCg(),
+ new CCh(),
+ new CCi(),
+ new CCj(),
+ new CCk(),
+ new CCl(),
+ new CCm(),
+ new CCn(),
+ new CCo(),
+ new CCp(),
+ new CCq(),
+ new CCr(),
+ new CCs(),
+ new CCt(),
+ new CCu(),
+ new CCv(),
+ new CCw(),
+ new CCx(),
+ new CCy(),
+ new CCz(),
+ new CCA(),
+ new CCB(),
+ new CCC(),
+ new CCD(),
+ new CCE(),
+ new CCF(),
+ new CCG(),
+ new CCH(),
+ new CCI(),
+ new CCJ(),
+ new CCK(),
+ new CCL(),
+ new CCM(),
+ new CCN(),
+ new CCO(),
+ new CCP(),
+ new CCQ(),
+ new CCR(),
+ new CCS(),
+ new CCT(),
+ new CCU(),
+ new CCV(),
+ new CCW(),
+ new CCX(),
+ new CCY(),
+ new CCZ(),
+ new CDa(),
+ new CDb(),
+ new CDc(),
+ new CDd(),
+ new CDe(),
+ new CDf(),
+ new CDg(),
+ new CDh(),
+ new CDi(),
+ new CDj(),
+ new CDk(),
+ new CDl(),
+ new CDm(),
+ new CDn(),
+ new CDo(),
+ new CDp(),
+ new CDq(),
+ new CDr(),
+ new CDs(),
+ new CDt(),
+ new CDu(),
+ new CDv(),
+ new CDw(),
+ new CDx(),
+ new CDy(),
+ new CDz(),
+ new CDA(),
+ new CDB(),
+ new CDC(),
+ new CDD(),
+ new CDE(),
+ new CDF(),
+ new CDG(),
+ new CDH(),
+ new CDI(),
+ new CDJ(),
+ new CDK(),
+ new CDL(),
+ new CDM(),
+ new CDN(),
+ new CDO(),
+ new CDP(),
+ new CDQ(),
+ new CDR(),
+ new CDS(),
+ new CDT(),
+ new CDU(),
+ new CDV(),
+ new CDW(),
+ new CDX(),
+ new CDY(),
+ new CDZ(),
+ new CEa(),
+ new CEb(),
+ new CEc(),
+ new CEd(),
+ new CEe(),
+ new CEf(),
+ new CEg(),
+ new CEh(),
+ new CEi(),
+ new CEj(),
+ new CEk(),
+ new CEl(),
+ new CEm(),
+ new CEn(),
+ new CEo(),
+ new CEp(),
+ new CEq(),
+ new CEr(),
+ new CEs(),
+ new CEt(),
+ new CEu(),
+ new CEv(),
+ new CEw(),
+ new CEx(),
+ new CEy(),
+ new CEz(),
+ new CEA(),
+ new CEB(),
+ new CEC(),
+ new CED(),
+ new CEE(),
+ new CEF(),
+ new CEG(),
+ new CEH(),
+ new CEI(),
+ new CEJ(),
+ new CEK(),
+ new CEL(),
+ new CEM(),
+ new CEN(),
+ new CEO(),
+ new CEP(),
+ new CEQ(),
+ new CER(),
+ new CES(),
+ new CET(),
+ new CEU(),
+ new CEV(),
+ new CEW(),
+ new CEX(),
+ new CEY(),
+ new CEZ(),
+ new CFa(),
+ new CFb(),
+ new CFc(),
+ new CFd(),
+ new CFe(),
+ new CFf(),
+ new CFg(),
+ new CFh(),
+ new CFi(),
+ new CFj(),
+ new CFk(),
+ new CFl(),
+ new CFm(),
+ new CFn(),
+ new CFo(),
+ new CFp(),
+ new CFq(),
+ new CFr(),
+ new CFs(),
+ new CFt(),
+ new CFu(),
+ new CFv(),
+ new CFw(),
+ new CFx(),
+ new CFy(),
+ new CFz(),
+ new CFA(),
+ new CFB(),
+ new CFC(),
+ new CFD(),
+ new CFE(),
+ new CFF(),
+ new CFG(),
+ new CFH(),
+ new CFI(),
+ new CFJ(),
+ new CFK(),
+ new CFL(),
+ new CFM(),
+ new CFN(),
+ new CFO(),
+ new CFP(),
+ new CFQ(),
+ new CFR(),
+ new CFS(),
+ new CFT(),
+ new CFU(),
+ new CFV(),
+ new CFW(),
+ new CFX(),
+ new CFY(),
+ new CFZ(),
+ new CGa(),
+ new CGb(),
+ new CGc(),
+ new CGd(),
+ new CGe(),
+ new CGf(),
+ new CGg(),
+ new CGh(),
+ new CGi(),
+ new CGj(),
+ new CGk(),
+ new CGl(),
+ new CGm(),
+ new CGn(),
+ new CGo(),
+ new CGp(),
+ new CGq(),
+ new CGr(),
+ new CGs(),
+ new CGt(),
+ new CGu(),
+ new CGv(),
+ new CGw(),
+ new CGx(),
+ new CGy(),
+ new CGz(),
+ new CGA(),
+ new CGB(),
+ new CGC(),
+ new CGD(),
+ new CGE(),
+ new CGF(),
+ new CGG(),
+ new CGH(),
+ new CGI(),
+ new CGJ(),
+ new CGK(),
+ new CGL(),
+ new CGM(),
+ new CGN(),
+ new CGO(),
+ new CGP(),
+ new CGQ(),
+ new CGR(),
+ new CGS(),
+ new CGT(),
+ new CGU(),
+ new CGV(),
+ new CGW(),
+ new CGX(),
+ new CGY(),
+ new CGZ(),
+ new CHa(),
+ new CHb(),
+ new CHc(),
+ new CHd(),
+ new CHe(),
+ new CHf(),
+ new CHg(),
+ new CHh(),
+ new CHi(),
+ new CHj(),
+ new CHk(),
+ new CHl(),
+ new CHm(),
+ new CHn(),
+ new CHo(),
+ new CHp(),
+ new CHq(),
+ new CHr(),
+ new CHs(),
+ new CHt(),
+ new CHu(),
+ new CHv(),
+ new CHw(),
+ new CHx(),
+ new CHy(),
+ new CHz(),
+ new CHA(),
+ new CHB(),
+ new CHC(),
+ new CHD(),
+ new CHE(),
+ new CHF(),
+ new CHG(),
+ new CHH(),
+ new CHI(),
+ new CHJ(),
+ new CHK(),
+ new CHL(),
+ new CHM(),
+ new CHN(),
+ new CHO(),
+ new CHP(),
+ new CHQ(),
+ new CHR(),
+ new CHS(),
+ new CHT(),
+ new CHU(),
+ new CHV(),
+ new CHW(),
+ new CHX(),
+ new CHY(),
+ new CHZ(),
+ new CIa(),
+ new CIb(),
+ new CIc(),
+ new CId(),
+ new CIe(),
+ new CIf(),
+ new CIg(),
+ new CIh(),
+ new CIi(),
+ new CIj(),
+ new CIk(),
+ new CIl(),
+ new CIm(),
+ new CIn(),
+ new CIo(),
+ new CIp(),
+ new CIq(),
+ new CIr(),
+ new CIs(),
+ new CIt(),
+ new CIu(),
+ new CIv(),
+ new CIw(),
+ new CIx(),
+ new CIy(),
+ new CIz(),
+ new CIA(),
+ new CIB(),
+ new CIC(),
+ new CID(),
+ new CIE(),
+ new CIF(),
+ new CIG(),
+ new CIH(),
+ new CII(),
+ new CIJ(),
+ new CIK(),
+ new CIL(),
+ new CIM(),
+ new CIN(),
+ new CIO(),
+ new CIP(),
+ new CIQ(),
+ new CIR(),
+ new CIS(),
+ new CIT(),
+ new CIU(),
+ new CIV(),
+ new CIW(),
+ new CIX(),
+ new CIY(),
+ new CIZ(),
+ new CJa(),
+ new CJb(),
+ new CJc(),
+ new CJd(),
+ new CJe(),
+ new CJf(),
+ new CJg(),
+ new CJh(),
+ new CJi(),
+ new CJj(),
+ new CJk(),
+ new CJl(),
+ new CJm(),
+ new CJn(),
+ new CJo(),
+ new CJp(),
+ new CJq(),
+ new CJr(),
+ new CJs(),
+ new CJt(),
+ new CJu(),
+ new CJv(),
+ new CJw(),
+ new CJx(),
+ new CJy(),
+ new CJz(),
+ new CJA(),
+ new CJB(),
+ new CJC(),
+ new CJD(),
+ new CJE(),
+ new CJF(),
+ new CJG(),
+ new CJH(),
+ new CJI(),
+ new CJJ(),
+ new CJK(),
+ new CJL(),
+ new CJM(),
+ new CJN(),
+ new CJO(),
+ new CJP(),
+ new CJQ(),
+ new CJR(),
+ new CJS(),
+ new CJT(),
+ new CJU(),
+ new CJV(),
+ new CJW(),
+ new CJX(),
+ new CJY(),
+ new CJZ(),
+ new CKa(),
+ new CKb(),
+ new CKc(),
+ new CKd(),
+ new CKe(),
+ new CKf(),
+ new CKg(),
+ new CKh(),
+ new CKi(),
+ new CKj(),
+ new CKk(),
+ new CKl(),
+ new CKm(),
+ new CKn(),
+ new CKo(),
+ new CKp(),
+ new CKq(),
+ new CKr(),
+ new CKs(),
+ new CKt(),
+ new CKu(),
+ new CKv(),
+ new CKw(),
+ new CKx(),
+ new CKy(),
+ new CKz(),
+ new CKA(),
+ new CKB(),
+ new CKC(),
+ new CKD(),
+ new CKE(),
+ new CKF(),
+ new CKG(),
+ new CKH(),
+ new CKI(),
+ new CKJ(),
+ new CKK(),
+ new CKL(),
+ new CKM(),
+ new CKN(),
+ new CKO(),
+ new CKP(),
+ new CKQ(),
+ new CKR(),
+ new CKS(),
+ new CKT(),
+ new CKU(),
+ new CKV(),
+ new CKW(),
+ new CKX(),
+ new CKY(),
+ new CKZ(),
+ new CLa(),
+ new CLb(),
+ new CLc(),
+ new CLd(),
+ new CLe(),
+ new CLf(),
+ new CLg(),
+ new CLh(),
+ new CLi(),
+ new CLj(),
+ new CLk(),
+ new CLl(),
+ new CLm(),
+ new CLn(),
+ new CLo(),
+ new CLp(),
+ new CLq(),
+ new CLr(),
+ new CLs(),
+ new CLt(),
+ new CLu(),
+ new CLv(),
+ new CLw(),
+ new CLx(),
+ new CLy(),
+ new CLz(),
+ new CLA(),
+ new CLB(),
+ new CLC(),
+ new CLD(),
+ new CLE(),
+ new CLF(),
+ new CLG(),
+ new CLH(),
+ new CLI(),
+ new CLJ(),
+ new CLK(),
+ new CLL(),
+ new CLM(),
+ new CLN(),
+ new CLO(),
+ new CLP(),
+ new CLQ(),
+ new CLR(),
+ new CLS(),
+ new CLT(),
+ new CLU(),
+ new CLV(),
+ new CLW(),
+ new CLX(),
+ new CLY(),
+ new CLZ(),
+ new CMa(),
+ new CMb(),
+ new CMc(),
+ new CMd(),
+ new CMe(),
+ new CMf(),
+ new CMg(),
+ new CMh(),
+ new CMi(),
+ new CMj(),
+ new CMk(),
+ new CMl(),
+ new CMm(),
+ new CMn(),
+ new CMo(),
+ new CMp(),
+ new CMq(),
+ new CMr(),
+ new CMs(),
+ new CMt(),
+ new CMu(),
+ new CMv(),
+ new CMw(),
+ new CMx(),
+ new CMy(),
+ new CMz(),
+ new CMA(),
+ new CMB(),
+ new CMC(),
+ new CMD(),
+ new CME(),
+ new CMF(),
+ new CMG(),
+ new CMH(),
+ new CMI(),
+ new CMJ(),
+ new CMK(),
+ new CML(),
+ new CMM(),
+ new CMN(),
+ new CMO(),
+ new CMP(),
+ new CMQ(),
+ new CMR(),
+ new CMS(),
+ new CMT(),
+ new CMU(),
+ new CMV(),
+ new CMW(),
+ new CMX(),
+ new CMY(),
+ new CMZ(),
+ new CNa(),
+ new CNb(),
+ new CNc(),
+ new CNd(),
+ new CNe(),
+ new CNf(),
+ new CNg(),
+ new CNh(),
+ new CNi(),
+ new CNj(),
+ new CNk(),
+ new CNl(),
+ new CNm(),
+ new CNn(),
+ new CNo(),
+ new CNp(),
+ new CNq(),
+ new CNr(),
+ new CNs(),
+ new CNt(),
+ new CNu(),
+ new CNv(),
+ new CNw(),
+ new CNx(),
+ new CNy(),
+ new CNz(),
+ new CNA(),
+ new CNB(),
+ new CNC(),
+ new CND(),
+ new CNE(),
+ new CNF(),
+ new CNG(),
+ new CNH(),
+ new CNI(),
+ new CNJ(),
+ new CNK(),
+ new CNL(),
+ new CNM(),
+ new CNN(),
+ new CNO(),
+ new CNP(),
+ new CNQ(),
+ new CNR(),
+ new CNS(),
+ new CNT(),
+ new CNU(),
+ new CNV(),
+ new CNW(),
+ new CNX(),
+ new CNY(),
+ new CNZ(),
+ new COa(),
+ new COb(),
+ new COc(),
+ new COd(),
+ new COe(),
+ new COf(),
+ new COg(),
+ new COh(),
+ new COi(),
+ new COj(),
+ new COk(),
+ new COl(),
+ new COm(),
+ new COn(),
+ new COo(),
+ new COp(),
+ new COq(),
+ new COr(),
+ new COs(),
+ new COt(),
+ new COu(),
+ new COv(),
+ new COw(),
+ new COx(),
+ new COy(),
+ new COz(),
+ new COA(),
+ new COB(),
+ new COC(),
+ new COD(),
+ new COE(),
+ new COF(),
+ new COG(),
+ new COH(),
+ new COI(),
+ new COJ(),
+ new COK(),
+ new COL(),
+ new COM(),
+ new CON(),
+ new COO(),
+ new COP(),
+ new COQ(),
+ new COR(),
+ new COS(),
+ new COT(),
+ new COU(),
+ new COV(),
+ new COW(),
+ new COX(),
+ new COY(),
+ new COZ(),
+ new CPa(),
+ new CPb(),
+ new CPc(),
+ new CPd(),
+ new CPe(),
+ new CPf(),
+ new CPg(),
+ new CPh(),
+ new CPi(),
+ new CPj(),
+ new CPk(),
+ new CPl(),
+ new CPm(),
+ new CPn(),
+ new CPo(),
+ new CPp(),
+ new CPq(),
+ new CPr(),
+ new CPs(),
+ new CPt(),
+ new CPu(),
+ new CPv(),
+ new CPw(),
+ new CPx(),
+ new CPy(),
+ new CPz(),
+ new CPA(),
+ new CPB(),
+ new CPC(),
+ new CPD(),
+ new CPE(),
+ new CPF(),
+ new CPG(),
+ new CPH(),
+ new CPI(),
+ new CPJ(),
+ new CPK(),
+ new CPL(),
+ new CPM(),
+ new CPN(),
+ new CPO(),
+ new CPP(),
+ new CPQ(),
+ new CPR(),
+ new CPS(),
+ new CPT(),
+ new CPU(),
+ new CPV(),
+ new CPW(),
+ new CPX(),
+ new CPY(),
+ new CPZ(),
+ new CQa(),
+ new CQb(),
+ new CQc(),
+ new CQd(),
+ new CQe(),
+ new CQf(),
+ new CQg(),
+ new CQh(),
+ new CQi(),
+ new CQj(),
+ new CQk(),
+ new CQl(),
+ new CQm(),
+ new CQn(),
+ new CQo(),
+ new CQp(),
+ new CQq(),
+ new CQr(),
+ new CQs(),
+ new CQt(),
+ new CQu(),
+ new CQv(),
+ new CQw(),
+ new CQx(),
+ new CQy(),
+ new CQz(),
+ new CQA(),
+ new CQB(),
+ new CQC(),
+ new CQD(),
+ new CQE(),
+ new CQF(),
+ new CQG(),
+ new CQH(),
+ new CQI(),
+ new CQJ(),
+ new CQK(),
+ new CQL(),
+ new CQM(),
+ new CQN(),
+ new CQO(),
+ new CQP(),
+ new CQQ(),
+ new CQR(),
+ new CQS(),
+ new CQT(),
+ new CQU(),
+ new CQV(),
+ new CQW(),
+ new CQX(),
+ new CQY(),
+ new CQZ(),
+ new CRa(),
+ new CRb(),
+ new CRc(),
+ new CRd(),
+ new CRe(),
+ new CRf(),
+ new CRg(),
+ new CRh(),
+ new CRi(),
+ new CRj(),
+ new CRk(),
+ new CRl(),
+ new CRm(),
+ new CRn(),
+ new CRo(),
+ new CRp(),
+ new CRq(),
+ new CRr(),
+ new CRs(),
+ new CRt(),
+ new CRu(),
+ new CRv(),
+ new CRw(),
+ new CRx(),
+ new CRy(),
+ new CRz(),
+ new CRA(),
+ new CRB(),
+ new CRC(),
+ new CRD(),
+ new CRE(),
+ new CRF(),
+ new CRG(),
+ new CRH(),
+ new CRI(),
+ new CRJ(),
+ new CRK(),
+ new CRL(),
+ new CRM(),
+ new CRN(),
+ new CRO(),
+ new CRP(),
+ new CRQ(),
+ new CRR(),
+ new CRS(),
+ new CRT(),
+ new CRU(),
+ new CRV(),
+ new CRW(),
+ new CRX(),
+ new CRY(),
+ new CRZ(),
+ new CSa(),
+ new CSb(),
+ new CSc(),
+ new CSd(),
+ new CSe(),
+ new CSf(),
+ new CSg(),
+ new CSh(),
+ new CSi(),
+ new CSj(),
+ new CSk(),
+ new CSl(),
+ new CSm(),
+ new CSn(),
+ new CSo(),
+ new CSp(),
+ new CSq(),
+ new CSr(),
+ new CSs(),
+ new CSt(),
+ new CSu(),
+ new CSv(),
+ new CSw(),
+ new CSx(),
+ new CSy(),
+ new CSz(),
+ new CSA(),
+ new CSB(),
+ new CSC(),
+ new CSD(),
+ new CSE(),
+ new CSF(),
+ new CSG(),
+ new CSH(),
+ new CSI(),
+ new CSJ(),
+ new CSK(),
+ new CSL(),
+ new CSM(),
+ new CSN(),
+ new CSO(),
+ new CSP(),
+ new CSQ(),
+ new CSR(),
+ new CSS(),
+ new CST(),
+ new CSU(),
+ new CSV(),
+ new CSW(),
+ new CSX(),
+ new CSY(),
+ new CSZ(),
+ new CTa(),
+ new CTb(),
+ new CTc(),
+ new CTd(),
+ new CTe(),
+ new CTf(),
+ new CTg(),
+ new CTh(),
+ new CTi(),
+ new CTj(),
+ new CTk(),
+ new CTl(),
+ new CTm(),
+ new CTn(),
+ new CTo(),
+ new CTp(),
+ new CTq(),
+ new CTr(),
+ new CTs(),
+ new CTt(),
+ new CTu(),
+ new CTv(),
+ new CTw(),
+ new CTx(),
+ new CTy(),
+ new CTz(),
+ new CTA(),
+ new CTB(),
+ new CTC(),
+ new CTD(),
+ new CTE(),
+ new CTF(),
+ new CTG(),
+ new CTH(),
+ new CTI(),
+ new CTJ(),
+ new CTK(),
+ new CTL(),
+ new CTM(),
+ new CTN(),
+ new CTO(),
+ new CTP(),
+ new CTQ(),
+ new CTR(),
+ new CTS(),
+ new CTT(),
+ new CTU(),
+ new CTV(),
+ new CTW(),
+ new CTX(),
+ new CTY(),
+ new CTZ(),
+ new CUa(),
+ new CUb(),
+ new CUc(),
+ new CUd(),
+ new CUe(),
+ new CUf(),
+ new CUg(),
+ new CUh(),
+ new CUi(),
+ new CUj(),
+ new CUk(),
+ new CUl(),
+ new CUm(),
+ new CUn(),
+ new CUo(),
+ new CUp(),
+ new CUq(),
+ new CUr(),
+ new CUs(),
+ new CUt(),
+ new CUu(),
+ new CUv(),
+ new CUw(),
+ new CUx(),
+ new CUy(),
+ new CUz(),
+ new CUA(),
+ new CUB(),
+ new CUC(),
+ new CUD(),
+ new CUE(),
+ new CUF(),
+ new CUG(),
+ new CUH(),
+ new CUI(),
+ new CUJ(),
+ new CUK(),
+ new CUL(),
+ new CUM(),
+ new CUN(),
+ new CUO(),
+ new CUP(),
+ new CUQ(),
+ new CUR(),
+ new CUS(),
+ new CUT(),
+ new CUU(),
+ new CUV(),
+ new CUW(),
+ new CUX(),
+ new CUY(),
+ new CUZ(),
+ new CVa(),
+ new CVb(),
+ new CVc(),
+ new CVd(),
+ new CVe(),
+ new CVf(),
+ new CVg(),
+ new CVh(),
+ new CVi(),
+ new CVj(),
+ new CVk(),
+ new CVl(),
+ new CVm(),
+ new CVn(),
+ new CVo(),
+ new CVp(),
+ new CVq(),
+ new CVr(),
+ new CVs(),
+ new CVt(),
+ new CVu(),
+ new CVv(),
+ new CVw(),
+ new CVx(),
+ new CVy(),
+ new CVz(),
+ new CVA(),
+ new CVB(),
+ new CVC(),
+ new CVD(),
+ new CVE(),
+ new CVF(),
+ new CVG(),
+ new CVH(),
+ new CVI(),
+ new CVJ(),
+ new CVK(),
+ new CVL(),
+ new CVM(),
+ new CVN(),
+ new CVO(),
+ new CVP(),
+ new CVQ(),
+ new CVR(),
+ new CVS(),
+ new CVT(),
+ new CVU(),
+ new CVV(),
+ new CVW(),
+ new CVX(),
+ new CVY(),
+ new CVZ(),
+ new CWa(),
+ new CWb(),
+ new CWc(),
+ new CWd(),
+ new CWe(),
+ new CWf(),
+ new CWg(),
+ new CWh(),
+ new CWi(),
+ new CWj(),
+ new CWk(),
+ new CWl(),
+ new CWm(),
+ new CWn(),
+ new CWo(),
+ new CWp(),
+ new CWq(),
+ new CWr(),
+ new CWs(),
+ new CWt(),
+ new CWu(),
+ new CWv(),
+ new CWw(),
+ new CWx(),
+ new CWy(),
+ new CWz(),
+ new CWA(),
+ new CWB(),
+ new CWC(),
+ new CWD(),
+ new CWE(),
+ new CWF(),
+ new CWG(),
+ new CWH(),
+ new CWI(),
+ new CWJ(),
+ new CWK(),
+ new CWL(),
+ new CWM(),
+ new CWN(),
+ new CWO(),
+ new CWP(),
+ new CWQ(),
+ new CWR(),
+ new CWS(),
+ new CWT(),
+ new CWU(),
+ new CWV(),
+ new CWW(),
+ new CWX(),
+ new CWY(),
+ new CWZ(),
+ new CXa(),
+ new CXb(),
+ new CXc(),
+ new CXd(),
+ new CXe(),
+ new CXf(),
+ new CXg(),
+ new CXh(),
+ new CXi(),
+ new CXj(),
+ new CXk(),
+ new CXl(),
+ new CXm(),
+ new CXn(),
+ new CXo(),
+ new CXp(),
+ new CXq(),
+ new CXr(),
+ new CXs(),
+ new CXt(),
+ new CXu(),
+ new CXv(),
+ new CXw(),
+ new CXx(),
+ new CXy(),
+ new CXz(),
+ new CXA(),
+ new CXB(),
+ new CXC(),
+ new CXD(),
+ new CXE(),
+ new CXF(),
+ new CXG(),
+ new CXH(),
+ new CXI(),
+ new CXJ(),
+ new CXK(),
+ new CXL(),
+ new CXM(),
+ new CXN(),
+ new CXO(),
+ new CXP(),
+ new CXQ(),
+ new CXR(),
+ new CXS(),
+ new CXT(),
+ new CXU(),
+ new CXV(),
+ new CXW(),
+ new CXX(),
+ new CXY(),
+ new CXZ(),
+ new CYa(),
+ new CYb(),
+ new CYc(),
+ new CYd(),
+ new CYe(),
+ new CYf(),
+ new CYg(),
+ new CYh(),
+ new CYi(),
+ new CYj(),
+ new CYk(),
+ new CYl(),
+ new CYm(),
+ new CYn(),
+ new CYo(),
+ new CYp(),
+ new CYq(),
+ new CYr(),
+ new CYs(),
+ new CYt(),
+ new CYu(),
+ new CYv(),
+ new CYw(),
+ new CYx(),
+ new CYy(),
+ new CYz(),
+ new CYA(),
+ new CYB(),
+ new CYC(),
+ new CYD(),
+ new CYE(),
+ new CYF(),
+ new CYG(),
+ new CYH(),
+ new CYI(),
+ new CYJ(),
+ new CYK(),
+ new CYL(),
+ new CYM(),
+ new CYN(),
+ new CYO(),
+ new CYP(),
+ new CYQ(),
+ new CYR(),
+ new CYS(),
+ new CYT(),
+ new CYU(),
+ new CYV(),
+ new CYW(),
+ new CYX(),
+ new CYY(),
+ new CYZ(),
+ new CZa(),
+ new CZb(),
+ new CZc(),
+ new CZd(),
+ new CZe(),
+ new CZf(),
+ new CZg(),
+ new CZh(),
+ new CZi(),
+ new CZj(),
+ new CZk(),
+ new CZl(),
+ new CZm(),
+ new CZn(),
+ new CZo(),
+ new CZp(),
+ new CZq(),
+ new CZr(),
+ new CZs(),
+ new CZt(),
+ new CZu(),
+ new CZv(),
+ new CZw(),
+ new CZx(),
+ new CZy(),
+ new CZz(),
+ new CZA(),
+ new CZB(),
+ new CZC(),
+ new CZD(),
+ new CZE(),
+ new CZF(),
+ new CZG(),
+ new CZH(),
+ new CZI(),
+ new CZJ(),
+ new CZK(),
+ new CZL(),
+ new CZM(),
+ new CZN(),
+ new CZO(),
+ new CZP(),
+ new CZQ(),
+ new CZR(),
+ new CZS(),
+ new CZT(),
+ new CZU(),
+ new CZV(),
+ new CZW(),
+ new CZX(),
+ new CZY(),
+ new CZZ(),
+];
+class Caa{}
+class Cab{}
+class Cac{}
+class Cad{}
+class Cae{}
+class Caf{}
+class Cag{}
+class Cah{}
+class Cai{}
+class Caj{}
+class Cak{}
+class Cal{}
+class Cam{}
+class Can{}
+class Cao{}
+class Cap{}
+class Caq{}
+class Car{}
+class Cas{}
+class Cat{}
+class Cau{}
+class Cav{}
+class Caw{}
+class Cax{}
+class Cay{}
+class Caz{}
+class CaA{}
+class CaB{}
+class CaC{}
+class CaD{}
+class CaE{}
+class CaF{}
+class CaG{}
+class CaH{}
+class CaI{}
+class CaJ{}
+class CaK{}
+class CaL{}
+class CaM{}
+class CaN{}
+class CaO{}
+class CaP{}
+class CaQ{}
+class CaR{}
+class CaS{}
+class CaT{}
+class CaU{}
+class CaV{}
+class CaW{}
+class CaX{}
+class CaY{}
+class CaZ{}
+class Cba{}
+class Cbb{}
+class Cbc{}
+class Cbd{}
+class Cbe{}
+class Cbf{}
+class Cbg{}
+class Cbh{}
+class Cbi{}
+class Cbj{}
+class Cbk{}
+class Cbl{}
+class Cbm{}
+class Cbn{}
+class Cbo{}
+class Cbp{}
+class Cbq{}
+class Cbr{}
+class Cbs{}
+class Cbt{}
+class Cbu{}
+class Cbv{}
+class Cbw{}
+class Cbx{}
+class Cby{}
+class Cbz{}
+class CbA{}
+class CbB{}
+class CbC{}
+class CbD{}
+class CbE{}
+class CbF{}
+class CbG{}
+class CbH{}
+class CbI{}
+class CbJ{}
+class CbK{}
+class CbL{}
+class CbM{}
+class CbN{}
+class CbO{}
+class CbP{}
+class CbQ{}
+class CbR{}
+class CbS{}
+class CbT{}
+class CbU{}
+class CbV{}
+class CbW{}
+class CbX{}
+class CbY{}
+class CbZ{}
+class Cca{}
+class Ccb{}
+class Ccc{}
+class Ccd{}
+class Cce{}
+class Ccf{}
+class Ccg{}
+class Cch{}
+class Cci{}
+class Ccj{}
+class Cck{}
+class Ccl{}
+class Ccm{}
+class Ccn{}
+class Cco{}
+class Ccp{}
+class Ccq{}
+class Ccr{}
+class Ccs{}
+class Cct{}
+class Ccu{}
+class Ccv{}
+class Ccw{}
+class Ccx{}
+class Ccy{}
+class Ccz{}
+class CcA{}
+class CcB{}
+class CcC{}
+class CcD{}
+class CcE{}
+class CcF{}
+class CcG{}
+class CcH{}
+class CcI{}
+class CcJ{}
+class CcK{}
+class CcL{}
+class CcM{}
+class CcN{}
+class CcO{}
+class CcP{}
+class CcQ{}
+class CcR{}
+class CcS{}
+class CcT{}
+class CcU{}
+class CcV{}
+class CcW{}
+class CcX{}
+class CcY{}
+class CcZ{}
+class Cda{}
+class Cdb{}
+class Cdc{}
+class Cdd{}
+class Cde{}
+class Cdf{}
+class Cdg{}
+class Cdh{}
+class Cdi{}
+class Cdj{}
+class Cdk{}
+class Cdl{}
+class Cdm{}
+class Cdn{}
+class Cdo{}
+class Cdp{}
+class Cdq{}
+class Cdr{}
+class Cds{}
+class Cdt{}
+class Cdu{}
+class Cdv{}
+class Cdw{}
+class Cdx{}
+class Cdy{}
+class Cdz{}
+class CdA{}
+class CdB{}
+class CdC{}
+class CdD{}
+class CdE{}
+class CdF{}
+class CdG{}
+class CdH{}
+class CdI{}
+class CdJ{}
+class CdK{}
+class CdL{}
+class CdM{}
+class CdN{}
+class CdO{}
+class CdP{}
+class CdQ{}
+class CdR{}
+class CdS{}
+class CdT{}
+class CdU{}
+class CdV{}
+class CdW{}
+class CdX{}
+class CdY{}
+class CdZ{}
+class Cea{}
+class Ceb{}
+class Cec{}
+class Ced{}
+class Cee{}
+class Cef{}
+class Ceg{}
+class Ceh{}
+class Cei{}
+class Cej{}
+class Cek{}
+class Cel{}
+class Cem{}
+class Cen{}
+class Ceo{}
+class Cep{}
+class Ceq{}
+class Cer{}
+class Ces{}
+class Cet{}
+class Ceu{}
+class Cev{}
+class Cew{}
+class Cex{}
+class Cey{}
+class Cez{}
+class CeA{}
+class CeB{}
+class CeC{}
+class CeD{}
+class CeE{}
+class CeF{}
+class CeG{}
+class CeH{}
+class CeI{}
+class CeJ{}
+class CeK{}
+class CeL{}
+class CeM{}
+class CeN{}
+class CeO{}
+class CeP{}
+class CeQ{}
+class CeR{}
+class CeS{}
+class CeT{}
+class CeU{}
+class CeV{}
+class CeW{}
+class CeX{}
+class CeY{}
+class CeZ{}
+class Cfa{}
+class Cfb{}
+class Cfc{}
+class Cfd{}
+class Cfe{}
+class Cff{}
+class Cfg{}
+class Cfh{}
+class Cfi{}
+class Cfj{}
+class Cfk{}
+class Cfl{}
+class Cfm{}
+class Cfn{}
+class Cfo{}
+class Cfp{}
+class Cfq{}
+class Cfr{}
+class Cfs{}
+class Cft{}
+class Cfu{}
+class Cfv{}
+class Cfw{}
+class Cfx{}
+class Cfy{}
+class Cfz{}
+class CfA{}
+class CfB{}
+class CfC{}
+class CfD{}
+class CfE{}
+class CfF{}
+class CfG{}
+class CfH{}
+class CfI{}
+class CfJ{}
+class CfK{}
+class CfL{}
+class CfM{}
+class CfN{}
+class CfO{}
+class CfP{}
+class CfQ{}
+class CfR{}
+class CfS{}
+class CfT{}
+class CfU{}
+class CfV{}
+class CfW{}
+class CfX{}
+class CfY{}
+class CfZ{}
+class Cga{}
+class Cgb{}
+class Cgc{}
+class Cgd{}
+class Cge{}
+class Cgf{}
+class Cgg{}
+class Cgh{}
+class Cgi{}
+class Cgj{}
+class Cgk{}
+class Cgl{}
+class Cgm{}
+class Cgn{}
+class Cgo{}
+class Cgp{}
+class Cgq{}
+class Cgr{}
+class Cgs{}
+class Cgt{}
+class Cgu{}
+class Cgv{}
+class Cgw{}
+class Cgx{}
+class Cgy{}
+class Cgz{}
+class CgA{}
+class CgB{}
+class CgC{}
+class CgD{}
+class CgE{}
+class CgF{}
+class CgG{}
+class CgH{}
+class CgI{}
+class CgJ{}
+class CgK{}
+class CgL{}
+class CgM{}
+class CgN{}
+class CgO{}
+class CgP{}
+class CgQ{}
+class CgR{}
+class CgS{}
+class CgT{}
+class CgU{}
+class CgV{}
+class CgW{}
+class CgX{}
+class CgY{}
+class CgZ{}
+class Cha{}
+class Chb{}
+class Chc{}
+class Chd{}
+class Che{}
+class Chf{}
+class Chg{}
+class Chh{}
+class Chi{}
+class Chj{}
+class Chk{}
+class Chl{}
+class Chm{}
+class Chn{}
+class Cho{}
+class Chp{}
+class Chq{}
+class Chr{}
+class Chs{}
+class Cht{}
+class Chu{}
+class Chv{}
+class Chw{}
+class Chx{}
+class Chy{}
+class Chz{}
+class ChA{}
+class ChB{}
+class ChC{}
+class ChD{}
+class ChE{}
+class ChF{}
+class ChG{}
+class ChH{}
+class ChI{}
+class ChJ{}
+class ChK{}
+class ChL{}
+class ChM{}
+class ChN{}
+class ChO{}
+class ChP{}
+class ChQ{}
+class ChR{}
+class ChS{}
+class ChT{}
+class ChU{}
+class ChV{}
+class ChW{}
+class ChX{}
+class ChY{}
+class ChZ{}
+class Cia{}
+class Cib{}
+class Cic{}
+class Cid{}
+class Cie{}
+class Cif{}
+class Cig{}
+class Cih{}
+class Cii{}
+class Cij{}
+class Cik{}
+class Cil{}
+class Cim{}
+class Cin{}
+class Cio{}
+class Cip{}
+class Ciq{}
+class Cir{}
+class Cis{}
+class Cit{}
+class Ciu{}
+class Civ{}
+class Ciw{}
+class Cix{}
+class Ciy{}
+class Ciz{}
+class CiA{}
+class CiB{}
+class CiC{}
+class CiD{}
+class CiE{}
+class CiF{}
+class CiG{}
+class CiH{}
+class CiI{}
+class CiJ{}
+class CiK{}
+class CiL{}
+class CiM{}
+class CiN{}
+class CiO{}
+class CiP{}
+class CiQ{}
+class CiR{}
+class CiS{}
+class CiT{}
+class CiU{}
+class CiV{}
+class CiW{}
+class CiX{}
+class CiY{}
+class CiZ{}
+class Cja{}
+class Cjb{}
+class Cjc{}
+class Cjd{}
+class Cje{}
+class Cjf{}
+class Cjg{}
+class Cjh{}
+class Cji{}
+class Cjj{}
+class Cjk{}
+class Cjl{}
+class Cjm{}
+class Cjn{}
+class Cjo{}
+class Cjp{}
+class Cjq{}
+class Cjr{}
+class Cjs{}
+class Cjt{}
+class Cju{}
+class Cjv{}
+class Cjw{}
+class Cjx{}
+class Cjy{}
+class Cjz{}
+class CjA{}
+class CjB{}
+class CjC{}
+class CjD{}
+class CjE{}
+class CjF{}
+class CjG{}
+class CjH{}
+class CjI{}
+class CjJ{}
+class CjK{}
+class CjL{}
+class CjM{}
+class CjN{}
+class CjO{}
+class CjP{}
+class CjQ{}
+class CjR{}
+class CjS{}
+class CjT{}
+class CjU{}
+class CjV{}
+class CjW{}
+class CjX{}
+class CjY{}
+class CjZ{}
+class Cka{}
+class Ckb{}
+class Ckc{}
+class Ckd{}
+class Cke{}
+class Ckf{}
+class Ckg{}
+class Ckh{}
+class Cki{}
+class Ckj{}
+class Ckk{}
+class Ckl{}
+class Ckm{}
+class Ckn{}
+class Cko{}
+class Ckp{}
+class Ckq{}
+class Ckr{}
+class Cks{}
+class Ckt{}
+class Cku{}
+class Ckv{}
+class Ckw{}
+class Ckx{}
+class Cky{}
+class Ckz{}
+class CkA{}
+class CkB{}
+class CkC{}
+class CkD{}
+class CkE{}
+class CkF{}
+class CkG{}
+class CkH{}
+class CkI{}
+class CkJ{}
+class CkK{}
+class CkL{}
+class CkM{}
+class CkN{}
+class CkO{}
+class CkP{}
+class CkQ{}
+class CkR{}
+class CkS{}
+class CkT{}
+class CkU{}
+class CkV{}
+class CkW{}
+class CkX{}
+class CkY{}
+class CkZ{}
+class Cla{}
+class Clb{}
+class Clc{}
+class Cld{}
+class Cle{}
+class Clf{}
+class Clg{}
+class Clh{}
+class Cli{}
+class Clj{}
+class Clk{}
+class Cll{}
+class Clm{}
+class Cln{}
+class Clo{}
+class Clp{}
+class Clq{}
+class Clr{}
+class Cls{}
+class Clt{}
+class Clu{}
+class Clv{}
+class Clw{}
+class Clx{}
+class Cly{}
+class Clz{}
+class ClA{}
+class ClB{}
+class ClC{}
+class ClD{}
+class ClE{}
+class ClF{}
+class ClG{}
+class ClH{}
+class ClI{}
+class ClJ{}
+class ClK{}
+class ClL{}
+class ClM{}
+class ClN{}
+class ClO{}
+class ClP{}
+class ClQ{}
+class ClR{}
+class ClS{}
+class ClT{}
+class ClU{}
+class ClV{}
+class ClW{}
+class ClX{}
+class ClY{}
+class ClZ{}
+class Cma{}
+class Cmb{}
+class Cmc{}
+class Cmd{}
+class Cme{}
+class Cmf{}
+class Cmg{}
+class Cmh{}
+class Cmi{}
+class Cmj{}
+class Cmk{}
+class Cml{}
+class Cmm{}
+class Cmn{}
+class Cmo{}
+class Cmp{}
+class Cmq{}
+class Cmr{}
+class Cms{}
+class Cmt{}
+class Cmu{}
+class Cmv{}
+class Cmw{}
+class Cmx{}
+class Cmy{}
+class Cmz{}
+class CmA{}
+class CmB{}
+class CmC{}
+class CmD{}
+class CmE{}
+class CmF{}
+class CmG{}
+class CmH{}
+class CmI{}
+class CmJ{}
+class CmK{}
+class CmL{}
+class CmM{}
+class CmN{}
+class CmO{}
+class CmP{}
+class CmQ{}
+class CmR{}
+class CmS{}
+class CmT{}
+class CmU{}
+class CmV{}
+class CmW{}
+class CmX{}
+class CmY{}
+class CmZ{}
+class Cna{}
+class Cnb{}
+class Cnc{}
+class Cnd{}
+class Cne{}
+class Cnf{}
+class Cng{}
+class Cnh{}
+class Cni{}
+class Cnj{}
+class Cnk{}
+class Cnl{}
+class Cnm{}
+class Cnn{}
+class Cno{}
+class Cnp{}
+class Cnq{}
+class Cnr{}
+class Cns{}
+class Cnt{}
+class Cnu{}
+class Cnv{}
+class Cnw{}
+class Cnx{}
+class Cny{}
+class Cnz{}
+class CnA{}
+class CnB{}
+class CnC{}
+class CnD{}
+class CnE{}
+class CnF{}
+class CnG{}
+class CnH{}
+class CnI{}
+class CnJ{}
+class CnK{}
+class CnL{}
+class CnM{}
+class CnN{}
+class CnO{}
+class CnP{}
+class CnQ{}
+class CnR{}
+class CnS{}
+class CnT{}
+class CnU{}
+class CnV{}
+class CnW{}
+class CnX{}
+class CnY{}
+class CnZ{}
+class Coa{}
+class Cob{}
+class Coc{}
+class Cod{}
+class Coe{}
+class Cof{}
+class Cog{}
+class Coh{}
+class Coi{}
+class Coj{}
+class Cok{}
+class Col{}
+class Com{}
+class Con{}
+class Coo{}
+class Cop{}
+class Coq{}
+class Cor{}
+class Cos{}
+class Cot{}
+class Cou{}
+class Cov{}
+class Cow{}
+class Cox{}
+class Coy{}
+class Coz{}
+class CoA{}
+class CoB{}
+class CoC{}
+class CoD{}
+class CoE{}
+class CoF{}
+class CoG{}
+class CoH{}
+class CoI{}
+class CoJ{}
+class CoK{}
+class CoL{}
+class CoM{}
+class CoN{}
+class CoO{}
+class CoP{}
+class CoQ{}
+class CoR{}
+class CoS{}
+class CoT{}
+class CoU{}
+class CoV{}
+class CoW{}
+class CoX{}
+class CoY{}
+class CoZ{}
+class Cpa{}
+class Cpb{}
+class Cpc{}
+class Cpd{}
+class Cpe{}
+class Cpf{}
+class Cpg{}
+class Cph{}
+class Cpi{}
+class Cpj{}
+class Cpk{}
+class Cpl{}
+class Cpm{}
+class Cpn{}
+class Cpo{}
+class Cpp{}
+class Cpq{}
+class Cpr{}
+class Cps{}
+class Cpt{}
+class Cpu{}
+class Cpv{}
+class Cpw{}
+class Cpx{}
+class Cpy{}
+class Cpz{}
+class CpA{}
+class CpB{}
+class CpC{}
+class CpD{}
+class CpE{}
+class CpF{}
+class CpG{}
+class CpH{}
+class CpI{}
+class CpJ{}
+class CpK{}
+class CpL{}
+class CpM{}
+class CpN{}
+class CpO{}
+class CpP{}
+class CpQ{}
+class CpR{}
+class CpS{}
+class CpT{}
+class CpU{}
+class CpV{}
+class CpW{}
+class CpX{}
+class CpY{}
+class CpZ{}
+class Cqa{}
+class Cqb{}
+class Cqc{}
+class Cqd{}
+class Cqe{}
+class Cqf{}
+class Cqg{}
+class Cqh{}
+class Cqi{}
+class Cqj{}
+class Cqk{}
+class Cql{}
+class Cqm{}
+class Cqn{}
+class Cqo{}
+class Cqp{}
+class Cqq{}
+class Cqr{}
+class Cqs{}
+class Cqt{}
+class Cqu{}
+class Cqv{}
+class Cqw{}
+class Cqx{}
+class Cqy{}
+class Cqz{}
+class CqA{}
+class CqB{}
+class CqC{}
+class CqD{}
+class CqE{}
+class CqF{}
+class CqG{}
+class CqH{}
+class CqI{}
+class CqJ{}
+class CqK{}
+class CqL{}
+class CqM{}
+class CqN{}
+class CqO{}
+class CqP{}
+class CqQ{}
+class CqR{}
+class CqS{}
+class CqT{}
+class CqU{}
+class CqV{}
+class CqW{}
+class CqX{}
+class CqY{}
+class CqZ{}
+class Cra{}
+class Crb{}
+class Crc{}
+class Crd{}
+class Cre{}
+class Crf{}
+class Crg{}
+class Crh{}
+class Cri{}
+class Crj{}
+class Crk{}
+class Crl{}
+class Crm{}
+class Crn{}
+class Cro{}
+class Crp{}
+class Crq{}
+class Crr{}
+class Crs{}
+class Crt{}
+class Cru{}
+class Crv{}
+class Crw{}
+class Crx{}
+class Cry{}
+class Crz{}
+class CrA{}
+class CrB{}
+class CrC{}
+class CrD{}
+class CrE{}
+class CrF{}
+class CrG{}
+class CrH{}
+class CrI{}
+class CrJ{}
+class CrK{}
+class CrL{}
+class CrM{}
+class CrN{}
+class CrO{}
+class CrP{}
+class CrQ{}
+class CrR{}
+class CrS{}
+class CrT{}
+class CrU{}
+class CrV{}
+class CrW{}
+class CrX{}
+class CrY{}
+class CrZ{}
+class Csa{}
+class Csb{}
+class Csc{}
+class Csd{}
+class Cse{}
+class Csf{}
+class Csg{}
+class Csh{}
+class Csi{}
+class Csj{}
+class Csk{}
+class Csl{}
+class Csm{}
+class Csn{}
+class Cso{}
+class Csp{}
+class Csq{}
+class Csr{}
+class Css{}
+class Cst{}
+class Csu{}
+class Csv{}
+class Csw{}
+class Csx{}
+class Csy{}
+class Csz{}
+class CsA{}
+class CsB{}
+class CsC{}
+class CsD{}
+class CsE{}
+class CsF{}
+class CsG{}
+class CsH{}
+class CsI{}
+class CsJ{}
+class CsK{}
+class CsL{}
+class CsM{}
+class CsN{}
+class CsO{}
+class CsP{}
+class CsQ{}
+class CsR{}
+class CsS{}
+class CsT{}
+class CsU{}
+class CsV{}
+class CsW{}
+class CsX{}
+class CsY{}
+class CsZ{}
+class Cta{}
+class Ctb{}
+class Ctc{}
+class Ctd{}
+class Cte{}
+class Ctf{}
+class Ctg{}
+class Cth{}
+class Cti{}
+class Ctj{}
+class Ctk{}
+class Ctl{}
+class Ctm{}
+class Ctn{}
+class Cto{}
+class Ctp{}
+class Ctq{}
+class Ctr{}
+class Cts{}
+class Ctt{}
+class Ctu{}
+class Ctv{}
+class Ctw{}
+class Ctx{}
+class Cty{}
+class Ctz{}
+class CtA{}
+class CtB{}
+class CtC{}
+class CtD{}
+class CtE{}
+class CtF{}
+class CtG{}
+class CtH{}
+class CtI{}
+class CtJ{}
+class CtK{}
+class CtL{}
+class CtM{}
+class CtN{}
+class CtO{}
+class CtP{}
+class CtQ{}
+class CtR{}
+class CtS{}
+class CtT{}
+class CtU{}
+class CtV{}
+class CtW{}
+class CtX{}
+class CtY{}
+class CtZ{}
+class Cua{}
+class Cub{}
+class Cuc{}
+class Cud{}
+class Cue{}
+class Cuf{}
+class Cug{}
+class Cuh{}
+class Cui{}
+class Cuj{}
+class Cuk{}
+class Cul{}
+class Cum{}
+class Cun{}
+class Cuo{}
+class Cup{}
+class Cuq{}
+class Cur{}
+class Cus{}
+class Cut{}
+class Cuu{}
+class Cuv{}
+class Cuw{}
+class Cux{}
+class Cuy{}
+class Cuz{}
+class CuA{}
+class CuB{}
+class CuC{}
+class CuD{}
+class CuE{}
+class CuF{}
+class CuG{}
+class CuH{}
+class CuI{}
+class CuJ{}
+class CuK{}
+class CuL{}
+class CuM{}
+class CuN{}
+class CuO{}
+class CuP{}
+class CuQ{}
+class CuR{}
+class CuS{}
+class CuT{}
+class CuU{}
+class CuV{}
+class CuW{}
+class CuX{}
+class CuY{}
+class CuZ{}
+class Cva{}
+class Cvb{}
+class Cvc{}
+class Cvd{}
+class Cve{}
+class Cvf{}
+class Cvg{}
+class Cvh{}
+class Cvi{}
+class Cvj{}
+class Cvk{}
+class Cvl{}
+class Cvm{}
+class Cvn{}
+class Cvo{}
+class Cvp{}
+class Cvq{}
+class Cvr{}
+class Cvs{}
+class Cvt{}
+class Cvu{}
+class Cvv{}
+class Cvw{}
+class Cvx{}
+class Cvy{}
+class Cvz{}
+class CvA{}
+class CvB{}
+class CvC{}
+class CvD{}
+class CvE{}
+class CvF{}
+class CvG{}
+class CvH{}
+class CvI{}
+class CvJ{}
+class CvK{}
+class CvL{}
+class CvM{}
+class CvN{}
+class CvO{}
+class CvP{}
+class CvQ{}
+class CvR{}
+class CvS{}
+class CvT{}
+class CvU{}
+class CvV{}
+class CvW{}
+class CvX{}
+class CvY{}
+class CvZ{}
+class Cwa{}
+class Cwb{}
+class Cwc{}
+class Cwd{}
+class Cwe{}
+class Cwf{}
+class Cwg{}
+class Cwh{}
+class Cwi{}
+class Cwj{}
+class Cwk{}
+class Cwl{}
+class Cwm{}
+class Cwn{}
+class Cwo{}
+class Cwp{}
+class Cwq{}
+class Cwr{}
+class Cws{}
+class Cwt{}
+class Cwu{}
+class Cwv{}
+class Cww{}
+class Cwx{}
+class Cwy{}
+class Cwz{}
+class CwA{}
+class CwB{}
+class CwC{}
+class CwD{}
+class CwE{}
+class CwF{}
+class CwG{}
+class CwH{}
+class CwI{}
+class CwJ{}
+class CwK{}
+class CwL{}
+class CwM{}
+class CwN{}
+class CwO{}
+class CwP{}
+class CwQ{}
+class CwR{}
+class CwS{}
+class CwT{}
+class CwU{}
+class CwV{}
+class CwW{}
+class CwX{}
+class CwY{}
+class CwZ{}
+class Cxa{}
+class Cxb{}
+class Cxc{}
+class Cxd{}
+class Cxe{}
+class Cxf{}
+class Cxg{}
+class Cxh{}
+class Cxi{}
+class Cxj{}
+class Cxk{}
+class Cxl{}
+class Cxm{}
+class Cxn{}
+class Cxo{}
+class Cxp{}
+class Cxq{}
+class Cxr{}
+class Cxs{}
+class Cxt{}
+class Cxu{}
+class Cxv{}
+class Cxw{}
+class Cxx{}
+class Cxy{}
+class Cxz{}
+class CxA{}
+class CxB{}
+class CxC{}
+class CxD{}
+class CxE{}
+class CxF{}
+class CxG{}
+class CxH{}
+class CxI{}
+class CxJ{}
+class CxK{}
+class CxL{}
+class CxM{}
+class CxN{}
+class CxO{}
+class CxP{}
+class CxQ{}
+class CxR{}
+class CxS{}
+class CxT{}
+class CxU{}
+class CxV{}
+class CxW{}
+class CxX{}
+class CxY{}
+class CxZ{}
+class Cya{}
+class Cyb{}
+class Cyc{}
+class Cyd{}
+class Cye{}
+class Cyf{}
+class Cyg{}
+class Cyh{}
+class Cyi{}
+class Cyj{}
+class Cyk{}
+class Cyl{}
+class Cym{}
+class Cyn{}
+class Cyo{}
+class Cyp{}
+class Cyq{}
+class Cyr{}
+class Cys{}
+class Cyt{}
+class Cyu{}
+class Cyv{}
+class Cyw{}
+class Cyx{}
+class Cyy{}
+class Cyz{}
+class CyA{}
+class CyB{}
+class CyC{}
+class CyD{}
+class CyE{}
+class CyF{}
+class CyG{}
+class CyH{}
+class CyI{}
+class CyJ{}
+class CyK{}
+class CyL{}
+class CyM{}
+class CyN{}
+class CyO{}
+class CyP{}
+class CyQ{}
+class CyR{}
+class CyS{}
+class CyT{}
+class CyU{}
+class CyV{}
+class CyW{}
+class CyX{}
+class CyY{}
+class CyZ{}
+class Cza{}
+class Czb{}
+class Czc{}
+class Czd{}
+class Cze{}
+class Czf{}
+class Czg{}
+class Czh{}
+class Czi{}
+class Czj{}
+class Czk{}
+class Czl{}
+class Czm{}
+class Czn{}
+class Czo{}
+class Czp{}
+class Czq{}
+class Czr{}
+class Czs{}
+class Czt{}
+class Czu{}
+class Czv{}
+class Czw{}
+class Czx{}
+class Czy{}
+class Czz{}
+class CzA{}
+class CzB{}
+class CzC{}
+class CzD{}
+class CzE{}
+class CzF{}
+class CzG{}
+class CzH{}
+class CzI{}
+class CzJ{}
+class CzK{}
+class CzL{}
+class CzM{}
+class CzN{}
+class CzO{}
+class CzP{}
+class CzQ{}
+class CzR{}
+class CzS{}
+class CzT{}
+class CzU{}
+class CzV{}
+class CzW{}
+class CzX{}
+class CzY{}
+class CzZ{}
+class CAa{}
+class CAb{}
+class CAc{}
+class CAd{}
+class CAe{}
+class CAf{}
+class CAg{}
+class CAh{}
+class CAi{}
+class CAj{}
+class CAk{}
+class CAl{}
+class CAm{}
+class CAn{}
+class CAo{}
+class CAp{}
+class CAq{}
+class CAr{}
+class CAs{}
+class CAt{}
+class CAu{}
+class CAv{}
+class CAw{}
+class CAx{}
+class CAy{}
+class CAz{}
+class CAA{}
+class CAB{}
+class CAC{}
+class CAD{}
+class CAE{}
+class CAF{}
+class CAG{}
+class CAH{}
+class CAI{}
+class CAJ{}
+class CAK{}
+class CAL{}
+class CAM{}
+class CAN{}
+class CAO{}
+class CAP{}
+class CAQ{}
+class CAR{}
+class CAS{}
+class CAT{}
+class CAU{}
+class CAV{}
+class CAW{}
+class CAX{}
+class CAY{}
+class CAZ{}
+class CBa{}
+class CBb{}
+class CBc{}
+class CBd{}
+class CBe{}
+class CBf{}
+class CBg{}
+class CBh{}
+class CBi{}
+class CBj{}
+class CBk{}
+class CBl{}
+class CBm{}
+class CBn{}
+class CBo{}
+class CBp{}
+class CBq{}
+class CBr{}
+class CBs{}
+class CBt{}
+class CBu{}
+class CBv{}
+class CBw{}
+class CBx{}
+class CBy{}
+class CBz{}
+class CBA{}
+class CBB{}
+class CBC{}
+class CBD{}
+class CBE{}
+class CBF{}
+class CBG{}
+class CBH{}
+class CBI{}
+class CBJ{}
+class CBK{}
+class CBL{}
+class CBM{}
+class CBN{}
+class CBO{}
+class CBP{}
+class CBQ{}
+class CBR{}
+class CBS{}
+class CBT{}
+class CBU{}
+class CBV{}
+class CBW{}
+class CBX{}
+class CBY{}
+class CBZ{}
+class CCa{}
+class CCb{}
+class CCc{}
+class CCd{}
+class CCe{}
+class CCf{}
+class CCg{}
+class CCh{}
+class CCi{}
+class CCj{}
+class CCk{}
+class CCl{}
+class CCm{}
+class CCn{}
+class CCo{}
+class CCp{}
+class CCq{}
+class CCr{}
+class CCs{}
+class CCt{}
+class CCu{}
+class CCv{}
+class CCw{}
+class CCx{}
+class CCy{}
+class CCz{}
+class CCA{}
+class CCB{}
+class CCC{}
+class CCD{}
+class CCE{}
+class CCF{}
+class CCG{}
+class CCH{}
+class CCI{}
+class CCJ{}
+class CCK{}
+class CCL{}
+class CCM{}
+class CCN{}
+class CCO{}
+class CCP{}
+class CCQ{}
+class CCR{}
+class CCS{}
+class CCT{}
+class CCU{}
+class CCV{}
+class CCW{}
+class CCX{}
+class CCY{}
+class CCZ{}
+class CDa{}
+class CDb{}
+class CDc{}
+class CDd{}
+class CDe{}
+class CDf{}
+class CDg{}
+class CDh{}
+class CDi{}
+class CDj{}
+class CDk{}
+class CDl{}
+class CDm{}
+class CDn{}
+class CDo{}
+class CDp{}
+class CDq{}
+class CDr{}
+class CDs{}
+class CDt{}
+class CDu{}
+class CDv{}
+class CDw{}
+class CDx{}
+class CDy{}
+class CDz{}
+class CDA{}
+class CDB{}
+class CDC{}
+class CDD{}
+class CDE{}
+class CDF{}
+class CDG{}
+class CDH{}
+class CDI{}
+class CDJ{}
+class CDK{}
+class CDL{}
+class CDM{}
+class CDN{}
+class CDO{}
+class CDP{}
+class CDQ{}
+class CDR{}
+class CDS{}
+class CDT{}
+class CDU{}
+class CDV{}
+class CDW{}
+class CDX{}
+class CDY{}
+class CDZ{}
+class CEa{}
+class CEb{}
+class CEc{}
+class CEd{}
+class CEe{}
+class CEf{}
+class CEg{}
+class CEh{}
+class CEi{}
+class CEj{}
+class CEk{}
+class CEl{}
+class CEm{}
+class CEn{}
+class CEo{}
+class CEp{}
+class CEq{}
+class CEr{}
+class CEs{}
+class CEt{}
+class CEu{}
+class CEv{}
+class CEw{}
+class CEx{}
+class CEy{}
+class CEz{}
+class CEA{}
+class CEB{}
+class CEC{}
+class CED{}
+class CEE{}
+class CEF{}
+class CEG{}
+class CEH{}
+class CEI{}
+class CEJ{}
+class CEK{}
+class CEL{}
+class CEM{}
+class CEN{}
+class CEO{}
+class CEP{}
+class CEQ{}
+class CER{}
+class CES{}
+class CET{}
+class CEU{}
+class CEV{}
+class CEW{}
+class CEX{}
+class CEY{}
+class CEZ{}
+class CFa{}
+class CFb{}
+class CFc{}
+class CFd{}
+class CFe{}
+class CFf{}
+class CFg{}
+class CFh{}
+class CFi{}
+class CFj{}
+class CFk{}
+class CFl{}
+class CFm{}
+class CFn{}
+class CFo{}
+class CFp{}
+class CFq{}
+class CFr{}
+class CFs{}
+class CFt{}
+class CFu{}
+class CFv{}
+class CFw{}
+class CFx{}
+class CFy{}
+class CFz{}
+class CFA{}
+class CFB{}
+class CFC{}
+class CFD{}
+class CFE{}
+class CFF{}
+class CFG{}
+class CFH{}
+class CFI{}
+class CFJ{}
+class CFK{}
+class CFL{}
+class CFM{}
+class CFN{}
+class CFO{}
+class CFP{}
+class CFQ{}
+class CFR{}
+class CFS{}
+class CFT{}
+class CFU{}
+class CFV{}
+class CFW{}
+class CFX{}
+class CFY{}
+class CFZ{}
+class CGa{}
+class CGb{}
+class CGc{}
+class CGd{}
+class CGe{}
+class CGf{}
+class CGg{}
+class CGh{}
+class CGi{}
+class CGj{}
+class CGk{}
+class CGl{}
+class CGm{}
+class CGn{}
+class CGo{}
+class CGp{}
+class CGq{}
+class CGr{}
+class CGs{}
+class CGt{}
+class CGu{}
+class CGv{}
+class CGw{}
+class CGx{}
+class CGy{}
+class CGz{}
+class CGA{}
+class CGB{}
+class CGC{}
+class CGD{}
+class CGE{}
+class CGF{}
+class CGG{}
+class CGH{}
+class CGI{}
+class CGJ{}
+class CGK{}
+class CGL{}
+class CGM{}
+class CGN{}
+class CGO{}
+class CGP{}
+class CGQ{}
+class CGR{}
+class CGS{}
+class CGT{}
+class CGU{}
+class CGV{}
+class CGW{}
+class CGX{}
+class CGY{}
+class CGZ{}
+class CHa{}
+class CHb{}
+class CHc{}
+class CHd{}
+class CHe{}
+class CHf{}
+class CHg{}
+class CHh{}
+class CHi{}
+class CHj{}
+class CHk{}
+class CHl{}
+class CHm{}
+class CHn{}
+class CHo{}
+class CHp{}
+class CHq{}
+class CHr{}
+class CHs{}
+class CHt{}
+class CHu{}
+class CHv{}
+class CHw{}
+class CHx{}
+class CHy{}
+class CHz{}
+class CHA{}
+class CHB{}
+class CHC{}
+class CHD{}
+class CHE{}
+class CHF{}
+class CHG{}
+class CHH{}
+class CHI{}
+class CHJ{}
+class CHK{}
+class CHL{}
+class CHM{}
+class CHN{}
+class CHO{}
+class CHP{}
+class CHQ{}
+class CHR{}
+class CHS{}
+class CHT{}
+class CHU{}
+class CHV{}
+class CHW{}
+class CHX{}
+class CHY{}
+class CHZ{}
+class CIa{}
+class CIb{}
+class CIc{}
+class CId{}
+class CIe{}
+class CIf{}
+class CIg{}
+class CIh{}
+class CIi{}
+class CIj{}
+class CIk{}
+class CIl{}
+class CIm{}
+class CIn{}
+class CIo{}
+class CIp{}
+class CIq{}
+class CIr{}
+class CIs{}
+class CIt{}
+class CIu{}
+class CIv{}
+class CIw{}
+class CIx{}
+class CIy{}
+class CIz{}
+class CIA{}
+class CIB{}
+class CIC{}
+class CID{}
+class CIE{}
+class CIF{}
+class CIG{}
+class CIH{}
+class CII{}
+class CIJ{}
+class CIK{}
+class CIL{}
+class CIM{}
+class CIN{}
+class CIO{}
+class CIP{}
+class CIQ{}
+class CIR{}
+class CIS{}
+class CIT{}
+class CIU{}
+class CIV{}
+class CIW{}
+class CIX{}
+class CIY{}
+class CIZ{}
+class CJa{}
+class CJb{}
+class CJc{}
+class CJd{}
+class CJe{}
+class CJf{}
+class CJg{}
+class CJh{}
+class CJi{}
+class CJj{}
+class CJk{}
+class CJl{}
+class CJm{}
+class CJn{}
+class CJo{}
+class CJp{}
+class CJq{}
+class CJr{}
+class CJs{}
+class CJt{}
+class CJu{}
+class CJv{}
+class CJw{}
+class CJx{}
+class CJy{}
+class CJz{}
+class CJA{}
+class CJB{}
+class CJC{}
+class CJD{}
+class CJE{}
+class CJF{}
+class CJG{}
+class CJH{}
+class CJI{}
+class CJJ{}
+class CJK{}
+class CJL{}
+class CJM{}
+class CJN{}
+class CJO{}
+class CJP{}
+class CJQ{}
+class CJR{}
+class CJS{}
+class CJT{}
+class CJU{}
+class CJV{}
+class CJW{}
+class CJX{}
+class CJY{}
+class CJZ{}
+class CKa{}
+class CKb{}
+class CKc{}
+class CKd{}
+class CKe{}
+class CKf{}
+class CKg{}
+class CKh{}
+class CKi{}
+class CKj{}
+class CKk{}
+class CKl{}
+class CKm{}
+class CKn{}
+class CKo{}
+class CKp{}
+class CKq{}
+class CKr{}
+class CKs{}
+class CKt{}
+class CKu{}
+class CKv{}
+class CKw{}
+class CKx{}
+class CKy{}
+class CKz{}
+class CKA{}
+class CKB{}
+class CKC{}
+class CKD{}
+class CKE{}
+class CKF{}
+class CKG{}
+class CKH{}
+class CKI{}
+class CKJ{}
+class CKK{}
+class CKL{}
+class CKM{}
+class CKN{}
+class CKO{}
+class CKP{}
+class CKQ{}
+class CKR{}
+class CKS{}
+class CKT{}
+class CKU{}
+class CKV{}
+class CKW{}
+class CKX{}
+class CKY{}
+class CKZ{}
+class CLa{}
+class CLb{}
+class CLc{}
+class CLd{}
+class CLe{}
+class CLf{}
+class CLg{}
+class CLh{}
+class CLi{}
+class CLj{}
+class CLk{}
+class CLl{}
+class CLm{}
+class CLn{}
+class CLo{}
+class CLp{}
+class CLq{}
+class CLr{}
+class CLs{}
+class CLt{}
+class CLu{}
+class CLv{}
+class CLw{}
+class CLx{}
+class CLy{}
+class CLz{}
+class CLA{}
+class CLB{}
+class CLC{}
+class CLD{}
+class CLE{}
+class CLF{}
+class CLG{}
+class CLH{}
+class CLI{}
+class CLJ{}
+class CLK{}
+class CLL{}
+class CLM{}
+class CLN{}
+class CLO{}
+class CLP{}
+class CLQ{}
+class CLR{}
+class CLS{}
+class CLT{}
+class CLU{}
+class CLV{}
+class CLW{}
+class CLX{}
+class CLY{}
+class CLZ{}
+class CMa{}
+class CMb{}
+class CMc{}
+class CMd{}
+class CMe{}
+class CMf{}
+class CMg{}
+class CMh{}
+class CMi{}
+class CMj{}
+class CMk{}
+class CMl{}
+class CMm{}
+class CMn{}
+class CMo{}
+class CMp{}
+class CMq{}
+class CMr{}
+class CMs{}
+class CMt{}
+class CMu{}
+class CMv{}
+class CMw{}
+class CMx{}
+class CMy{}
+class CMz{}
+class CMA{}
+class CMB{}
+class CMC{}
+class CMD{}
+class CME{}
+class CMF{}
+class CMG{}
+class CMH{}
+class CMI{}
+class CMJ{}
+class CMK{}
+class CML{}
+class CMM{}
+class CMN{}
+class CMO{}
+class CMP{}
+class CMQ{}
+class CMR{}
+class CMS{}
+class CMT{}
+class CMU{}
+class CMV{}
+class CMW{}
+class CMX{}
+class CMY{}
+class CMZ{}
+class CNa{}
+class CNb{}
+class CNc{}
+class CNd{}
+class CNe{}
+class CNf{}
+class CNg{}
+class CNh{}
+class CNi{}
+class CNj{}
+class CNk{}
+class CNl{}
+class CNm{}
+class CNn{}
+class CNo{}
+class CNp{}
+class CNq{}
+class CNr{}
+class CNs{}
+class CNt{}
+class CNu{}
+class CNv{}
+class CNw{}
+class CNx{}
+class CNy{}
+class CNz{}
+class CNA{}
+class CNB{}
+class CNC{}
+class CND{}
+class CNE{}
+class CNF{}
+class CNG{}
+class CNH{}
+class CNI{}
+class CNJ{}
+class CNK{}
+class CNL{}
+class CNM{}
+class CNN{}
+class CNO{}
+class CNP{}
+class CNQ{}
+class CNR{}
+class CNS{}
+class CNT{}
+class CNU{}
+class CNV{}
+class CNW{}
+class CNX{}
+class CNY{}
+class CNZ{}
+class COa{}
+class COb{}
+class COc{}
+class COd{}
+class COe{}
+class COf{}
+class COg{}
+class COh{}
+class COi{}
+class COj{}
+class COk{}
+class COl{}
+class COm{}
+class COn{}
+class COo{}
+class COp{}
+class COq{}
+class COr{}
+class COs{}
+class COt{}
+class COu{}
+class COv{}
+class COw{}
+class COx{}
+class COy{}
+class COz{}
+class COA{}
+class COB{}
+class COC{}
+class COD{}
+class COE{}
+class COF{}
+class COG{}
+class COH{}
+class COI{}
+class COJ{}
+class COK{}
+class COL{}
+class COM{}
+class CON{}
+class COO{}
+class COP{}
+class COQ{}
+class COR{}
+class COS{}
+class COT{}
+class COU{}
+class COV{}
+class COW{}
+class COX{}
+class COY{}
+class COZ{}
+class CPa{}
+class CPb{}
+class CPc{}
+class CPd{}
+class CPe{}
+class CPf{}
+class CPg{}
+class CPh{}
+class CPi{}
+class CPj{}
+class CPk{}
+class CPl{}
+class CPm{}
+class CPn{}
+class CPo{}
+class CPp{}
+class CPq{}
+class CPr{}
+class CPs{}
+class CPt{}
+class CPu{}
+class CPv{}
+class CPw{}
+class CPx{}
+class CPy{}
+class CPz{}
+class CPA{}
+class CPB{}
+class CPC{}
+class CPD{}
+class CPE{}
+class CPF{}
+class CPG{}
+class CPH{}
+class CPI{}
+class CPJ{}
+class CPK{}
+class CPL{}
+class CPM{}
+class CPN{}
+class CPO{}
+class CPP{}
+class CPQ{}
+class CPR{}
+class CPS{}
+class CPT{}
+class CPU{}
+class CPV{}
+class CPW{}
+class CPX{}
+class CPY{}
+class CPZ{}
+class CQa{}
+class CQb{}
+class CQc{}
+class CQd{}
+class CQe{}
+class CQf{}
+class CQg{}
+class CQh{}
+class CQi{}
+class CQj{}
+class CQk{}
+class CQl{}
+class CQm{}
+class CQn{}
+class CQo{}
+class CQp{}
+class CQq{}
+class CQr{}
+class CQs{}
+class CQt{}
+class CQu{}
+class CQv{}
+class CQw{}
+class CQx{}
+class CQy{}
+class CQz{}
+class CQA{}
+class CQB{}
+class CQC{}
+class CQD{}
+class CQE{}
+class CQF{}
+class CQG{}
+class CQH{}
+class CQI{}
+class CQJ{}
+class CQK{}
+class CQL{}
+class CQM{}
+class CQN{}
+class CQO{}
+class CQP{}
+class CQQ{}
+class CQR{}
+class CQS{}
+class CQT{}
+class CQU{}
+class CQV{}
+class CQW{}
+class CQX{}
+class CQY{}
+class CQZ{}
+class CRa{}
+class CRb{}
+class CRc{}
+class CRd{}
+class CRe{}
+class CRf{}
+class CRg{}
+class CRh{}
+class CRi{}
+class CRj{}
+class CRk{}
+class CRl{}
+class CRm{}
+class CRn{}
+class CRo{}
+class CRp{}
+class CRq{}
+class CRr{}
+class CRs{}
+class CRt{}
+class CRu{}
+class CRv{}
+class CRw{}
+class CRx{}
+class CRy{}
+class CRz{}
+class CRA{}
+class CRB{}
+class CRC{}
+class CRD{}
+class CRE{}
+class CRF{}
+class CRG{}
+class CRH{}
+class CRI{}
+class CRJ{}
+class CRK{}
+class CRL{}
+class CRM{}
+class CRN{}
+class CRO{}
+class CRP{}
+class CRQ{}
+class CRR{}
+class CRS{}
+class CRT{}
+class CRU{}
+class CRV{}
+class CRW{}
+class CRX{}
+class CRY{}
+class CRZ{}
+class CSa{}
+class CSb{}
+class CSc{}
+class CSd{}
+class CSe{}
+class CSf{}
+class CSg{}
+class CSh{}
+class CSi{}
+class CSj{}
+class CSk{}
+class CSl{}
+class CSm{}
+class CSn{}
+class CSo{}
+class CSp{}
+class CSq{}
+class CSr{}
+class CSs{}
+class CSt{}
+class CSu{}
+class CSv{}
+class CSw{}
+class CSx{}
+class CSy{}
+class CSz{}
+class CSA{}
+class CSB{}
+class CSC{}
+class CSD{}
+class CSE{}
+class CSF{}
+class CSG{}
+class CSH{}
+class CSI{}
+class CSJ{}
+class CSK{}
+class CSL{}
+class CSM{}
+class CSN{}
+class CSO{}
+class CSP{}
+class CSQ{}
+class CSR{}
+class CSS{}
+class CST{}
+class CSU{}
+class CSV{}
+class CSW{}
+class CSX{}
+class CSY{}
+class CSZ{}
+class CTa{}
+class CTb{}
+class CTc{}
+class CTd{}
+class CTe{}
+class CTf{}
+class CTg{}
+class CTh{}
+class CTi{}
+class CTj{}
+class CTk{}
+class CTl{}
+class CTm{}
+class CTn{}
+class CTo{}
+class CTp{}
+class CTq{}
+class CTr{}
+class CTs{}
+class CTt{}
+class CTu{}
+class CTv{}
+class CTw{}
+class CTx{}
+class CTy{}
+class CTz{}
+class CTA{}
+class CTB{}
+class CTC{}
+class CTD{}
+class CTE{}
+class CTF{}
+class CTG{}
+class CTH{}
+class CTI{}
+class CTJ{}
+class CTK{}
+class CTL{}
+class CTM{}
+class CTN{}
+class CTO{}
+class CTP{}
+class CTQ{}
+class CTR{}
+class CTS{}
+class CTT{}
+class CTU{}
+class CTV{}
+class CTW{}
+class CTX{}
+class CTY{}
+class CTZ{}
+class CUa{}
+class CUb{}
+class CUc{}
+class CUd{}
+class CUe{}
+class CUf{}
+class CUg{}
+class CUh{}
+class CUi{}
+class CUj{}
+class CUk{}
+class CUl{}
+class CUm{}
+class CUn{}
+class CUo{}
+class CUp{}
+class CUq{}
+class CUr{}
+class CUs{}
+class CUt{}
+class CUu{}
+class CUv{}
+class CUw{}
+class CUx{}
+class CUy{}
+class CUz{}
+class CUA{}
+class CUB{}
+class CUC{}
+class CUD{}
+class CUE{}
+class CUF{}
+class CUG{}
+class CUH{}
+class CUI{}
+class CUJ{}
+class CUK{}
+class CUL{}
+class CUM{}
+class CUN{}
+class CUO{}
+class CUP{}
+class CUQ{}
+class CUR{}
+class CUS{}
+class CUT{}
+class CUU{}
+class CUV{}
+class CUW{}
+class CUX{}
+class CUY{}
+class CUZ{}
+class CVa{}
+class CVb{}
+class CVc{}
+class CVd{}
+class CVe{}
+class CVf{}
+class CVg{}
+class CVh{}
+class CVi{}
+class CVj{}
+class CVk{}
+class CVl{}
+class CVm{}
+class CVn{}
+class CVo{}
+class CVp{}
+class CVq{}
+class CVr{}
+class CVs{}
+class CVt{}
+class CVu{}
+class CVv{}
+class CVw{}
+class CVx{}
+class CVy{}
+class CVz{}
+class CVA{}
+class CVB{}
+class CVC{}
+class CVD{}
+class CVE{}
+class CVF{}
+class CVG{}
+class CVH{}
+class CVI{}
+class CVJ{}
+class CVK{}
+class CVL{}
+class CVM{}
+class CVN{}
+class CVO{}
+class CVP{}
+class CVQ{}
+class CVR{}
+class CVS{}
+class CVT{}
+class CVU{}
+class CVV{}
+class CVW{}
+class CVX{}
+class CVY{}
+class CVZ{}
+class CWa{}
+class CWb{}
+class CWc{}
+class CWd{}
+class CWe{}
+class CWf{}
+class CWg{}
+class CWh{}
+class CWi{}
+class CWj{}
+class CWk{}
+class CWl{}
+class CWm{}
+class CWn{}
+class CWo{}
+class CWp{}
+class CWq{}
+class CWr{}
+class CWs{}
+class CWt{}
+class CWu{}
+class CWv{}
+class CWw{}
+class CWx{}
+class CWy{}
+class CWz{}
+class CWA{}
+class CWB{}
+class CWC{}
+class CWD{}
+class CWE{}
+class CWF{}
+class CWG{}
+class CWH{}
+class CWI{}
+class CWJ{}
+class CWK{}
+class CWL{}
+class CWM{}
+class CWN{}
+class CWO{}
+class CWP{}
+class CWQ{}
+class CWR{}
+class CWS{}
+class CWT{}
+class CWU{}
+class CWV{}
+class CWW{}
+class CWX{}
+class CWY{}
+class CWZ{}
+class CXa{}
+class CXb{}
+class CXc{}
+class CXd{}
+class CXe{}
+class CXf{}
+class CXg{}
+class CXh{}
+class CXi{}
+class CXj{}
+class CXk{}
+class CXl{}
+class CXm{}
+class CXn{}
+class CXo{}
+class CXp{}
+class CXq{}
+class CXr{}
+class CXs{}
+class CXt{}
+class CXu{}
+class CXv{}
+class CXw{}
+class CXx{}
+class CXy{}
+class CXz{}
+class CXA{}
+class CXB{}
+class CXC{}
+class CXD{}
+class CXE{}
+class CXF{}
+class CXG{}
+class CXH{}
+class CXI{}
+class CXJ{}
+class CXK{}
+class CXL{}
+class CXM{}
+class CXN{}
+class CXO{}
+class CXP{}
+class CXQ{}
+class CXR{}
+class CXS{}
+class CXT{}
+class CXU{}
+class CXV{}
+class CXW{}
+class CXX{}
+class CXY{}
+class CXZ{}
+class CYa{}
+class CYb{}
+class CYc{}
+class CYd{}
+class CYe{}
+class CYf{}
+class CYg{}
+class CYh{}
+class CYi{}
+class CYj{}
+class CYk{}
+class CYl{}
+class CYm{}
+class CYn{}
+class CYo{}
+class CYp{}
+class CYq{}
+class CYr{}
+class CYs{}
+class CYt{}
+class CYu{}
+class CYv{}
+class CYw{}
+class CYx{}
+class CYy{}
+class CYz{}
+class CYA{}
+class CYB{}
+class CYC{}
+class CYD{}
+class CYE{}
+class CYF{}
+class CYG{}
+class CYH{}
+class CYI{}
+class CYJ{}
+class CYK{}
+class CYL{}
+class CYM{}
+class CYN{}
+class CYO{}
+class CYP{}
+class CYQ{}
+class CYR{}
+class CYS{}
+class CYT{}
+class CYU{}
+class CYV{}
+class CYW{}
+class CYX{}
+class CYY{}
+class CYZ{}
+class CZa{}
+class CZb{}
+class CZc{}
+class CZd{}
+class CZe{}
+class CZf{}
+class CZg{}
+class CZh{}
+class CZi{}
+class CZj{}
+class CZk{}
+class CZl{}
+class CZm{}
+class CZn{}
+class CZo{}
+class CZp{}
+class CZq{}
+class CZr{}
+class CZs{}
+class CZt{}
+class CZu{}
+class CZv{}
+class CZw{}
+class CZx{}
+class CZy{}
+class CZz{}
+class CZA{}
+class CZB{}
+class CZC{}
+class CZD{}
+class CZE{}
+class CZF{}
+class CZG{}
+class CZH{}
+class CZI{}
+class CZJ{}
+class CZK{}
+class CZL{}
+class CZM{}
+class CZN{}
+class CZO{}
+class CZP{}
+class CZQ{}
+class CZR{}
+class CZS{}
+class CZT{}
+class CZU{}
+class CZV{}
+class CZW{}
+class CZX{}
+class CZY{}
+class CZZ{}
+
diff --git a/tests/language/conditional_access_helper.dart b/tests/language/conditional_access_helper.dart
index 108857a..c847232 100644
--- a/tests/language/conditional_access_helper.dart
+++ b/tests/language/conditional_access_helper.dart
@@ -14,6 +14,26 @@
void topLevelFunction() {}
class C {
- static var staticField;
- static void staticMethod() {}
+ static int staticInt;
+ static staticF(callback()) => callback();
+ static int staticG(int callback()) => callback();
}
+
+C nullC() => null;
+
+class D {
+ static E staticE;
+}
+
+class E {
+ G operator+(int i) => new I();
+ G operator-(int i) => new I();
+}
+
+class F {}
+
+class G extends E implements F {}
+
+class H {}
+
+class I extends G implements H {}
diff --git a/tests/language/conditional_method_invocation_test.dart b/tests/language/conditional_method_invocation_test.dart
index cfe0545..0dd219d 100644
--- a/tests/language/conditional_method_invocation_test.dart
+++ b/tests/language/conditional_method_invocation_test.dart
@@ -18,7 +18,8 @@
class C extends B {
f(callback()) => callback();
int g(int callback()) => callback();
- static void staticMethod() {}
+ static staticF(callback()) => callback();
+ static int staticG(int callback()) => callback();
}
C nullC() => null;
@@ -32,12 +33,20 @@
Expect.equals(null, nullC()?.f(bad())); /// 01: ok
Expect.equals(1, new C()?.f(() => 1)); /// 02: ok
+ // C?.m(...) is equivalent to C.m(...).
+ Expect.equals(1, C?.staticF(() => 1)); /// 14: ok
+ Expect.equals(1, h.C?.staticF(() => 1)); /// 15: ok
+
// The static type of o?.m(...) is the same as the static type of
// o.m(...).
{ int i = nullC()?.g(bad()); Expect.equals(null, i); } /// 03: ok
{ int i = new C()?.g(() => 1); Expect.equals(1, i); } /// 04: ok
{ String s = nullC()?.g(bad()); Expect.equals(null, s); } /// 05: static type warning
{ String s = new C()?.g(() => null); Expect.equals(null, s); } /// 06: static type warning
+ { int i = C?.staticG(() => 1); Expect.equals(1, i); } /// 16: ok
+ { int i = h.C?.staticG(() => 1); Expect.equals(1, i); } /// 17: ok
+ { String s = C?.staticG(() => null); Expect.equals(null, s); } /// 18: static type warning
+ { String s = h.C?.staticG(() => null); Expect.equals(null, s); } /// 19: static type warning
// Let T be the static type of o and let y be a fresh variable of type T.
// Exactly the same static warnings that would be caused by y.m(...) are also
@@ -45,15 +54,11 @@
{ B b = new C(); Expect.equals(1, b?.f(() => 1)); } /// 07: static type warning
{ int i = 1; Expect.equals(null, nullC()?.f(i)); } /// 08: static type warning
- // Consequently, '?.' cannot be used to invoke static methods of classes.
- Expect.throws(() => C?.staticMethod(), noMethod); /// 09: static type warning
- Expect.throws(() => h.C?.staticMethod(), noMethod); /// 10: static type warning
-
- // Nor can it be used to access toplevel functions in libraries imported via
+ // '?.' can't be used to access toplevel functions in libraries imported via
// prefix.
h?.topLevelFunction(); /// 11: compile-time error
- // However, '?.' can be used to access the toString method on the class Type.
- Expect.equals(C?.toString(), (C).toString()); /// 12: ok
- Expect.equals(h.C?.toString(), (h.C).toString()); /// 13: ok
+ // Nor can it be used to access the toString method on the class Type.
+ Expect.throws(() => C?.toString(), noMethod); /// 12: static type warning
+ Expect.throws(() => h.C?.toString(), noMethod); /// 13: static type warning
}
diff --git a/tests/language/conditional_property_access_test.dart b/tests/language/conditional_property_access_test.dart
index ca44f2d..b5dfa85 100644
--- a/tests/language/conditional_property_access_test.dart
+++ b/tests/language/conditional_property_access_test.dart
@@ -15,7 +15,7 @@
class C extends B {
int v;
C(this.v);
- static var staticField;
+ static int staticInt;
}
C nullC() => null;
@@ -29,9 +29,17 @@
Expect.equals(null, nullC()?.v); /// 01: ok
Expect.equals(1, new C(1)?.v); /// 02: ok
+ // C?.id is equivalent to C.id.
+ { C.staticInt = 1; Expect.equals(1, C?.staticInt); } /// 12: ok
+ { h.C.staticInt = 1; Expect.equals(1, h.C?.staticInt); } /// 13: ok
+
// The static type of e1?.d is the static type of e1.id.
{ int i = new C(1)?.v; Expect.equals(1, i); } /// 03: ok
{ String s = new C(null)?.v; Expect.equals(null, s); } /// 04: static type warning
+ { C.staticInt = 1; int i = C?.staticInt; Expect.equals(1, i); } /// 14: ok
+ { h.C.staticInt = 1; int i = h.C?.staticInt; Expect.equals(1, i); } /// 15: ok
+ { C.staticInt = null; String s = C?.staticInt; Expect.equals(null, s); } /// 16: static type warning
+ { h.C.staticInt = null; String s = h.C?.staticInt; Expect.equals(null, s); } /// 17: static type warning
// Let T be the static type of e1 and let y be a fresh variable of type T.
// Exactly the same static warnings that would be caused by y.id are also
@@ -39,15 +47,11 @@
Expect.equals(null, nullC()?.bad); /// 05: static type warning
{ B b = new C(1); Expect.equals(1, b?.v); } /// 06: static type warning
- // Consequently, '?.' cannot be used to access static properties of classes.
- Expect.throws(() => C?.staticField, noMethod); /// 07: static type warning
- Expect.throws(() => h.C?.staticField, noMethod); /// 08: static type warning
-
- // Nor can it be used to access toplevel properties in libraries imported via
+ // '?.' cannot be used to access toplevel properties in libraries imported via
// prefix.
var x = h?.topLevelVar; /// 09: compile-time error
- // However, '?.' can be used to access the hashCode getter on the class Type.
- Expect.equals(C?.hashCode, (C).hashCode); /// 10: ok
- Expect.equals(h.C?.hashCode, (h.C).hashCode); /// 11: ok
+ // Nor can it be used to access the hashCode getter on the class Type.
+ Expect.throws(() => C?.hashCode, noMethod); /// 10: static type warning
+ Expect.throws(() => h.C?.hashCode, noMethod); /// 11: static type warning
}
diff --git a/tests/language/conditional_property_assignment_test.dart b/tests/language/conditional_property_assignment_test.dart
index 87e2bd0..1207198 100644
--- a/tests/language/conditional_property_assignment_test.dart
+++ b/tests/language/conditional_property_assignment_test.dart
@@ -19,12 +19,13 @@
class C extends B {
int v;
C(this.v);
- static var staticField;
+ static int staticInt;
}
class D {
E v;
D(this.v);
+ static E staticE;
}
class E {
@@ -50,9 +51,17 @@
Expect.equals(null, nullC()?.v = bad()); /// 01: ok
{ C c = new C(1); Expect.equals(2, c?.v = 2); Expect.equals(2, c.v); } /// 02: ok
+ // C?.v = e2 is equivalent to C.v = e2.
+ { C.staticInt = 1; Expect.equals(2, C?.staticInt = 2); Expect.equals(2, C.staticInt); } /// 23: ok
+ { h.C.staticInt = 1; Expect.equals(2, h.C?.staticInt = 2); Expect.equals(2, h.C.staticInt); } /// 24: ok
+
// The static type of e1?.v = e2 is the static type of e2.
{ D d = new D(new E()); G g = new G(); F f = (d?.v = g); Expect.identical(f, g); } /// 03: ok
{ D d = new D(new E()); E e = new G(); F f = (d?.v = e); Expect.identical(f, e); } /// 04: static type warning
+ { D.staticE = new E(); G g = new G(); F f = (D?.staticE = g); Expect.identical(f, g); } /// 25: ok
+ { h.D.staticE = new h.E(); h.G g = new h.G(); h.F f = (h.D?.staticE = g); Expect.identical(f, g); } /// 26: ok
+ { D.staticE = new E(); E e = new G(); F f = (D?.staticE = e); Expect.identical(f, e); } /// 27: static type warning
+ { h.D.staticE = new h.E(); h.E e = new h.G(); h.F f = (h.D?.staticE = e); Expect.identical(f, e); } /// 28: static type warning
// Exactly the same static warnings that would be caused by e1.v = e2 are
// also generated in the case of e1?.v = e2.
@@ -63,8 +72,13 @@
Expect.equals(null, nullC()?.v += bad()); /// 07: ok
{ C c = new C(1); Expect.equals(3, c?.v += 2); Expect.equals(3, c.v); } /// 08: ok
+ // C?.v op= e2 is equivalent to C.v op= e2.
+ { C.staticInt = 1; Expect.equals(3, C?.staticInt += 2); Expect.equals(3, C?.staticInt); } /// 29: ok
+
// The static type of e1?.v op= e2 is the static type of e1.v op e2.
{ D d = new D(new E()); F f = (d?.v += 1); Expect.identical(d.v, f); } /// 09: ok
+ { D.staticE = new E(); F f = (D?.staticE += 1); Expect.identical(D.staticE, f); } /// 30: ok
+ { h.D.staticE = new h.E(); h.F f = (h.D?.staticE += 1); Expect.identical(h.D.staticE, f); } /// 31: ok
// Let T be the static type of e1 and let y be a fresh variable of type T.
// Exactly the same static warnings that would be caused by y.v op e2 are
@@ -73,17 +87,12 @@
{ B b = new C(1); Expect.equals(3, b?.v += 2); Expect.equals(3, (b as C).v); } /// 11: static type warning
{ D d = new D(new E()); F f = (d?.v += nullC()); Expect.identical(d.v, f); } /// 12: static type warning
{ D d = new D(new E()); H h = (d?.v += 1); Expect.identical(d.v, h); } /// 13: static type warning
+ { D.staticE = new E(); F f = (D?.staticE += nullC()); Expect.identical(D.staticE, f); } /// 32: static type warning
+ { h.D.staticE = new h.E(); h.F f = (h.D?.staticE += h.nullC()); Expect.identical(h.D.staticE, f); } /// 33: static type warning
+ { D.staticE = new E(); H h = (D?.staticE += 1); Expect.identical(D.staticE, h); } /// 34: static type warning
+ { h.D.staticE = new h.E(); h.H hh = (h.D?.staticE += 1); Expect.identical(h.D.staticE, hh); } /// 35: static type warning
- // Consequently, '?.' cannot be used to assign to static properties of
- // classes.
- Expect.throws(() => C?.staticField = null, noMethod); /// 14: static type warning
- Expect.throws(() => C?.staticField += null, noMethod); /// 15: static type warning
- Expect.throws(() => C?.staticField ??= null, noMethod); /// 16: static type warning
- Expect.throws(() => h.C?.staticField = null, noMethod); /// 17: static type warning
- Expect.throws(() => h.C?.staticField += null, noMethod); /// 18: static type warning
- Expect.throws(() => h.C?.staticField ??= null, noMethod); /// 19: static type warning
-
- // Nor can it be used to assign to toplevel properties in libraries imported
+ // '?.' cannot be used to assign to toplevel properties in libraries imported
// via prefix.
h?.topLevelVar = null; /// 20: compile-time error
h?.topLevelVar += null; /// 21: compile-time error
diff --git a/tests/language/conditional_property_increment_decrement_test.dart b/tests/language/conditional_property_increment_decrement_test.dart
index 6858a69..81a27c6 100644
--- a/tests/language/conditional_property_increment_decrement_test.dart
+++ b/tests/language/conditional_property_increment_decrement_test.dart
@@ -6,16 +6,18 @@
// preincrement expression (or a postdecrement or predecrement expression).
import "package:expect/expect.dart";
+import "conditional_access_helper.dart" as h;
class C {
int v;
C(this.v);
- static var staticField;
+ static int staticInt;
}
class D {
E v;
D(this.v);
+ static E staticE;
}
class E {
@@ -42,31 +44,63 @@
Expect.equals(null, nullC()?.v++); /// 01: ok
{ C c = new C(1); Expect.equals(1, c?.v++); Expect.equals(2, c.v); } /// 02: ok
+ // C?.v++ is equivalent to C.v++.
+ { C.staticInt = 1; Expect.equals(1, C?.staticInt++); Expect.equals(2, C.staticInt); } /// 17: ok
+ { h.C.staticInt = 1; Expect.equals(1, h.C?.staticInt++); Expect.equals(2, h.C.staticInt); } /// 18: ok
+
// The static type of e1?.v++ is the same as the static type of e1.v.
{ E e1 = new E(); D d = new D(e1); E e2 = d?.v++; Expect.identical(e1, e2); } /// 03: ok
{ G g = new G(); D d = new D(g); F f = d?.v++; Expect.identical(f, g); } /// 04: static type warning
+ { E e1 = new E(); D.staticE = e1; E e2 = D?.staticE++; Expect.identical(e1, e2); } /// 19: ok
+ { h.E e1 = new h.E(); h.D.staticE = e1; h.E e2 = h.D?.staticE++; Expect.identical(e1, e2); } /// 20: ok
+ { G g = new G(); D.staticE = g; F f = D?.staticE++; Expect.identical(f, g); } /// 21: static type warning
+ { h.G g = new h.G(); h.D.staticE = g; h.F f = h.D?.staticE++; Expect.identical(f, g); } /// 22: static type warning
// e1?.v-- is equivalent to ((x) => x == null ? null : x.v--)(e1).
Expect.equals(null, nullC()?.v--); /// 05: ok
{ C c = new C(1); Expect.equals(1, c?.v--); Expect.equals(0, c.v); } /// 06: ok
+ // C?.v-- is equivalent to C.v--.
+ { C.staticInt = 1; Expect.equals(1, C?.staticInt--); Expect.equals(0, C.staticInt); } /// 23: ok
+ { h.C.staticInt = 1; Expect.equals(1, h.C?.staticInt--); Expect.equals(0, h.C.staticInt); } /// 24: ok
+
// The static type of e1?.v-- is the same as the static type of e1.v.
{ E e1 = new E(); D d = new D(e1); E e2 = d?.v--; Expect.identical(e1, e2); } /// 07: ok
{ G g = new G(); D d = new D(g); F f = d?.v--; Expect.identical(f, g); } /// 08: static type warning
+ { E e1 = new E(); D.staticE = e1; E e2 = D?.staticE--; Expect.identical(e1, e2); } /// 25: ok
+ { h.E e1 = new h.E(); h.D.staticE = e1; h.E e2 = h.D?.staticE--; Expect.identical(e1, e2); } /// 26: ok
+ { G g = new G(); D.staticE = g; F f = D?.staticE--; Expect.identical(f, g); } /// 27: static type warning
+ { h.G g = new h.G(); h.D.staticE = g; h.F f = h.D?.staticE--; Expect.identical(f, g); } /// 28: static type warning
// ++e1?.v is equivalent to e1?.v += 1.
Expect.equals(null, ++nullC()?.v); /// 09: ok
{ C c = new C(1); Expect.equals(2, ++c?.v); Expect.equals(2, c.v); } /// 10: ok
+ // ++C?.v is equivalent to C?.v += 1.
+ { C.staticInt = 1; Expect.equals(2, ++C?.staticInt); Expect.equals(2, C.staticInt); } /// 29: ok
+ { h.C.staticInt = 1; Expect.equals(2, ++h.C?.staticInt); Expect.equals(2, h.C.staticInt); } /// 30: ok
+
// The static type of ++e1?.v is the same as the static type of e1.v + 1.
{ D d = new D(new E()); F f = ++d?.v; Expect.identical(d.v, f); } /// 11: ok
{ D d = new D(new E()); H h = ++d?.v; Expect.identical(d.v, h); } /// 12: static type warning
+ { D.staticE = new E(); F f = ++D?.staticE; Expect.identical(D.staticE, f); } /// 31: ok
+ { h.D.staticE = new h.E(); h.F f = ++h.D?.staticE; Expect.identical(h.D.staticE, f); } /// 32: ok
+ { D.staticE = new E(); H h = ++D?.staticE; Expect.identical(D.staticE, h); } /// 33: static type warning
+ { h.D.staticE = new h.E(); h.H hh = ++h.D?.staticE; Expect.identical(h.D.staticE, hh); } /// 34: static type warning
- // --e1?.v is equivalent to e1?.v += 1.
+ // --e1?.v is equivalent to e1?.v -= 1.
Expect.equals(null, --nullC()?.v); /// 13: ok
{ C c = new C(1); Expect.equals(0, --c?.v); Expect.equals(0, c.v); } /// 14: ok
+ // --C?.v is equivalent to C?.v -= 1.
+ { C.staticInt = 1; Expect.equals(0, --C?.staticInt); Expect.equals(0, C.staticInt); } /// 35: ok
+ { h.C.staticInt = 1; Expect.equals(0, --h.C?.staticInt); Expect.equals(0, h.C.staticInt); } /// 36: ok
+
// The static type of --e1?.v is the same as the static type of e1.v - 1.
{ D d = new D(new E()); F f = --d?.v; Expect.identical(d.v, f); } /// 15: ok
{ D d = new D(new E()); H h = --d?.v; Expect.identical(d.v, h); } /// 16: static type warning
+ { D.staticE = new E(); F f = --D?.staticE; Expect.identical(D.staticE, f); } /// 37: ok
+ { h.D.staticE = new h.E(); h.F f = --h.D?.staticE; Expect.identical(h.D.staticE, f); } /// 38: ok
+ { D.staticE = new E(); H h = --D?.staticE; Expect.identical(D.staticE, h); } /// 39: static type warning
+ { h.D.staticE = new h.E(); h.H hh = --h.D?.staticE; Expect.identical(h.D.staticE, hh); } /// 40: static type warning
}
diff --git a/tests/language/const_syntax_test.dart b/tests/language/const_syntax_test.dart
index 668bb9f..59fb362 100644
--- a/tests/language/const_syntax_test.dart
+++ b/tests/language/const_syntax_test.dart
@@ -32,6 +32,13 @@
Expect.equals("Hello 42", B2);
Expect.equals("42Hello", B3); /// 10: compile-time error
+
+ const cf1 = identical(const Point(1, 2), const Point(1, 2));
+
+ const cf2 = identical(const Point(1, 2), new Point(1, 2)); /// 11: compile-time error
+
+ var f4 = B4; /// 12: compile-time error
+ var f5 = B5;
}
const F0 = 42;
@@ -75,3 +82,8 @@
const B1 = "Hello";
const B2 = "$B1 $B0";
const B3 = B0 + B1; /// 10: continued
+
+// Check identical.
+
+const B4 = identical(1, new Point(1,2)); /// 12: compile-time error
+const B5 = identical(1, const Point(1,2));
diff --git a/tests/language/cyclic_default_values_test.dart b/tests/language/cyclic_default_values_test.dart
new file mode 100644
index 0000000..9d7f664
--- /dev/null
+++ b/tests/language/cyclic_default_values_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+bar([x = foo]) => x((_) => "bar");
+foo([y = bar]) => y((_) => "foo");
+
+foo2({f: bar2}) => f(f: ({f}) => "foo2");
+bar2({f: foo2}) => f(f: ({f}) => "bar2");
+
+main() {
+ var f = bar;
+ Expect.equals("bar", Function.apply(f, []));
+ Expect.equals("main", Function.apply(f, [(_) => "main"]));
+
+ f = bar2;
+ Expect.equals("bar2", Function.apply(f, []));
+ Expect.equals("main2", Function.apply(f, [], {#f: ({f}) => "main2"}));
+}
diff --git a/tests/language/deferred_type_dependency_lib1.dart b/tests/language/deferred_type_dependency_lib1.dart
new file mode 100644
index 0000000..b9bac0d
--- /dev/null
+++ b/tests/language/deferred_type_dependency_lib1.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart Team. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+
+library lib1;
+
+import "deferred_type_dependency_lib3.dart";
+
+bool fooIs(x) {
+ return x is A;
+}
+
+bool fooAs(x) {
+ try {
+ return (x as A).p;
+ } on CastError catch (e) {
+ return false;
+ }
+}
+
+bool fooAnnotation(x) {
+ try {
+ A y = x;
+ return y is! String;
+ } on TypeError catch (e) {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/tests/language/deferred_type_dependency_lib2.dart b/tests/language/deferred_type_dependency_lib2.dart
new file mode 100644
index 0000000..e6954e5
--- /dev/null
+++ b/tests/language/deferred_type_dependency_lib2.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2015, the Dart Team. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+
+library lib2;
+
+import "deferred_type_dependency_lib3.dart";
+
+getInstance() {
+ return new A();
+}
\ No newline at end of file
diff --git a/tests/language/deferred_type_dependency_lib3.dart b/tests/language/deferred_type_dependency_lib3.dart
new file mode 100644
index 0000000..9a23fc9
--- /dev/null
+++ b/tests/language/deferred_type_dependency_lib3.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library lib3;
+
+class A {
+ var p = true;
+}
+
diff --git a/tests/language/deferred_type_dependency_test.dart b/tests/language/deferred_type_dependency_test.dart
new file mode 100644
index 0000000..766834e
--- /dev/null
+++ b/tests/language/deferred_type_dependency_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2015, the Dart Team. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+
+/// Checks that lib1.fooX's dependencies on [A] via is-checks, as-expressions
+/// and type-annotations(in checked-mode) is correctly tracked.
+
+import "deferred_type_dependency_lib1.dart" deferred as lib1;
+import "deferred_type_dependency_lib2.dart" deferred as lib2;
+import "package:expect/expect.dart";
+
+main() async {
+ await lib1.loadLibrary();
+ // Split the cases into a multi-test to test each feature separately.
+ Expect.isFalse(
+ lib1.fooIs /// is: ok
+ lib1.fooAs /// as: ok
+ lib1.fooAnnotation /// type_annotation: ok
+ ("string")
+ is! String /// none: ok
+ );
+ await lib2.loadLibrary();
+ Expect.isTrue(
+ lib1.fooIs /// is: ok
+ lib1.fooAs /// as: ok
+ lib1.fooAnnotation /// type_annotation: ok
+ (lib2.getInstance())
+ is! String /// none: ok
+ );
+}
\ No newline at end of file
diff --git a/tests/language/if_null_assignment_behavior_test.dart b/tests/language/if_null_assignment_behavior_test.dart
index bf01dbe..765be96 100644
--- a/tests/language/if_null_assignment_behavior_test.dart
+++ b/tests/language/if_null_assignment_behavior_test.dart
@@ -201,4 +201,14 @@
check(1, () => x?.v ??= bad(), ['x', 'x.v']); /// 27: continued
xGetValue = new C('x'); yGetValue = 1; /// 28: ok
check(1, () => x?.v ??= y, ['x', 'x.v', 'y', 'x.v=1']); /// 28: continued
+
+ // C?.v ??= e2 is equivalent to C.v ??= e2.
+ C.xGetValue = 1; /// 29: ok
+ check(1, () => C?.x ??= bad(), ['C.x']); /// 29: continued
+ h.C.xgetValue = 1; /// 30: ok
+ check(1, () => h.c?.x ??= bad(), ['h.C.x']); /// 30: continued
+ yGetValue = 1; /// 31: ok
+ check(1, () => C?.x ??= y, ['C.x', 'y', 'C.x=1']); /// 31: continued
+ yGetValue = 1; /// 32: ok
+ check(1, () => h.C?.x ??= y, ['h.C.x', 'y', 'h.C.x=1']); /// 32: continued
}
diff --git a/tests/language/indirect_const_null_test.dart b/tests/language/indirect_const_null_test.dart
new file mode 100644
index 0000000..5161614
--- /dev/null
+++ b/tests/language/indirect_const_null_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+ const NULL = 1 == 1 ? null : false;
+ Expect.isNull(NULL);
+}
diff --git a/tests/language/issue21079_test.dart b/tests/language/issue21079_test.dart
new file mode 100644
index 0000000..e41c46e
--- /dev/null
+++ b/tests/language/issue21079_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test case for http://dartbug.com/21079
+import 'dart:mirrors';
+import 'dart:isolate';
+import "package:expect/expect.dart";
+
+void main() {
+ Expect.isTrue(reflectClass(MyException).superclass.reflectedType == IsolateSpawnException);
+
+ Expect.isTrue(reflectClass(IsolateSpawnException).reflectedType == IsolateSpawnException);
+}
+
+class MyException extends IsolateSpawnException {
+ MyException() : super("Test") {}
+}
+
+
diff --git a/tests/language/issue23244_test.dart b/tests/language/issue23244_test.dart
new file mode 100644
index 0000000..b155769
--- /dev/null
+++ b/tests/language/issue23244_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test case for http://dartbug.com/23244
+import 'dart:async';
+import 'dart:isolate';
+
+enum Fisk {
+ torsk,
+}
+
+isolate1(SendPort port) {
+ port.send(Fisk.torsk);
+}
+
+isolate2(SendPort port) {
+ port.send([Fisk.torsk]);
+}
+
+isolate3(SendPort port) {
+ var x = new Map<int, Fisk>();
+ x[0] = Fisk.torsk;
+ x[1] = Fisk.torsk;
+ port.send(x);
+}
+
+main() async {
+ var port = new ReceivePort();
+ await Isolate.spawn(isolate1, port.sendPort);
+ Completer completer1 = new Completer();
+ port.listen((message) {
+ print("Received $message");
+ port.close();
+ expectTorsk(message);
+ completer1.complete();
+ });
+ await completer1.future;
+ Completer completer2 = new Completer();
+ port = new ReceivePort();
+ await Isolate.spawn(isolate2, port.sendPort);
+ port.listen((message) {
+ print("Received $message");
+ port.close();
+ expectTorsk(message[0]);
+ completer2.complete();
+ });
+ await completer2.future;
+ port = new ReceivePort();
+ await Isolate.spawn(isolate3, port.sendPort);
+ port.listen((message) {
+ print("Received $message");
+ port.close();
+ expectTorsk(message[0]);
+ expectTorsk(message[1]);
+ });
+}
+
+expectTorsk(Fisk fisk) {
+ if (fisk != Fisk.torsk) {
+ throw "$fisk isn't a ${Fisk.torsk}";
+ }
+}
+
diff --git a/tests/language/issue_23914_test.dart b/tests/language/issue_23914_test.dart
new file mode 100644
index 0000000..072f912
--- /dev/null
+++ b/tests/language/issue_23914_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+main() {
+ var a = new List.unmodifiable(new LinkedList());
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 44d45bf..2f58a23 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -7,6 +7,7 @@
[ $compiler == none ]
built_in_identifier_prefix_test: Fail # Issue 6970
+tearoff_constructor_basic_test: Skip # Crashes in checked mode -- hausner investigating
# These bugs refer currently ongoing language discussions.
constructor_initializer_test/none: Fail # Issue 12633
@@ -17,14 +18,9 @@
# Regular bugs which should be fixed.
duplicate_export_negative_test: Fail # Issue 6134
-[ $compiler == none ]
-
deferred_redirecting_factory_test: Fail # Issue 23408
redirecting_constructor_initializer_test: RuntimeError # Issue 23488
-[ $compiler == none && $runtime != dartium && $runtime != drt ]
-
-[ $compiler == none ]
# Non-contractive types are not supported in the vm.
cyclic_type_test/02: Fail, OK
cyclic_type_test/04: Fail, OK
@@ -47,6 +43,61 @@
[ $compiler == none ]
dynamic_prefix_core_test/01: RuntimeError # Issue 12478
multiline_strings_test: Fail # Issue 23020
+conditional_method_invocation_test/12: Fail # Issue 23794
+conditional_method_invocation_test/13: Fail # Issue 23794
+conditional_method_invocation_test/14: Fail # Issue 23794
+conditional_method_invocation_test/15: Fail # Issue 23794
+conditional_method_invocation_test/16: Fail # Issue 23794
+conditional_method_invocation_test/17: Fail # Issue 23794
+conditional_method_invocation_test/18: Fail # Issue 23794
+conditional_method_invocation_test/19: Fail # Issue 23794
+conditional_property_access_test/10: Fail # Issue 23794
+conditional_property_access_test/11: Fail # Issue 23794
+conditional_property_access_test/12: Fail # Issue 23794
+conditional_property_access_test/13: Fail # Issue 23794
+conditional_property_access_test/14: Fail # Issue 23794
+conditional_property_access_test/15: Fail # Issue 23794
+conditional_property_access_test/16: Fail # Issue 23794
+conditional_property_access_test/17: Fail # Issue 23794
+conditional_property_assignment_test/23: Fail # Issue 23794
+conditional_property_assignment_test/24: Fail # Issue 23794
+conditional_property_assignment_test/25: Fail # Issue 23794
+conditional_property_assignment_test/26: Fail # Issue 23794
+conditional_property_assignment_test/27: Fail # Issue 23794
+conditional_property_assignment_test/28: Fail # Issue 23794
+conditional_property_assignment_test/29: Fail # Issue 23794
+conditional_property_assignment_test/30: Fail # Issue 23794
+conditional_property_assignment_test/31: Fail # Issue 23794
+conditional_property_assignment_test/32: Fail # Issue 23794
+conditional_property_assignment_test/33: Fail # Issue 23794
+conditional_property_assignment_test/34: Fail # Issue 23794
+conditional_property_assignment_test/35: Fail # Issue 23794
+conditional_property_increment_decrement_test/17: Fail # Issue 23794
+conditional_property_increment_decrement_test/18: Fail # Issue 23794
+conditional_property_increment_decrement_test/19: Fail # Issue 23794
+conditional_property_increment_decrement_test/20: Fail # Issue 23794
+conditional_property_increment_decrement_test/21: Fail # Issue 23794
+conditional_property_increment_decrement_test/22: Fail # Issue 23794
+conditional_property_increment_decrement_test/23: Fail # Issue 23794
+conditional_property_increment_decrement_test/24: Fail # Issue 23794
+conditional_property_increment_decrement_test/25: Fail # Issue 23794
+conditional_property_increment_decrement_test/26: Fail # Issue 23794
+conditional_property_increment_decrement_test/27: Fail # Issue 23794
+conditional_property_increment_decrement_test/28: Fail # Issue 23794
+conditional_property_increment_decrement_test/29: Fail # Issue 23794
+conditional_property_increment_decrement_test/30: Fail # Issue 23794
+conditional_property_increment_decrement_test/31: Fail # Issue 23794
+conditional_property_increment_decrement_test/32: Fail # Issue 23794
+conditional_property_increment_decrement_test/33: Fail # Issue 23794
+conditional_property_increment_decrement_test/34: Fail # Issue 23794
+conditional_property_increment_decrement_test/35: Fail # Issue 23794
+conditional_property_increment_decrement_test/36: Fail # Issue 23794
+conditional_property_increment_decrement_test/37: Fail # Issue 23794
+conditional_property_increment_decrement_test/38: Fail # Issue 23794
+conditional_property_increment_decrement_test/39: Fail # Issue 23794
+conditional_property_increment_decrement_test/40: Fail # Issue 23794
+if_null_assignment_behavior_test/31: Fail # Issue 23794
+if_null_assignment_behavior_test/32: Fail # Issue 23794
[ $compiler == none && ($runtime == vm || $runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
dynamic_prefix_core_test/none: Fail # Issue 12478
@@ -97,6 +148,7 @@
[ $compiler == none && $runtime == vm && ( $arch == simarm || $arch == arm || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
-[ $compiler == none && $runtime == dartium ]
+[ $compiler == none && ( $runtime == dartium || $runtime == drt ) ]
mixin_super_test: Fail # Can't pass VMOptions to dartium.
mixin_super_bound2_test: Fail # Can't pass VMOptions to dartium.
+issue23244_test: Fail # Can't run spawnFunction on dartium.
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index b86fe4b..bb3cf05 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -17,6 +17,8 @@
getter_setter_in_lib_test: Fail # issue 23286
issue13179_test: CompileTimeError # Issue 13179
+tearoff_basic_test: Skip # Tear-off not supported
+tearoff_constructor_basic_test: Skip # Tear-off not supported
sync_generator2_test/01: MissingCompileTimeError # Issue 22252
sync_generator2_test/02: MissingCompileTimeError # Issue 22252
@@ -76,6 +78,13 @@
mixin_super_constructor_positionals_test/01: MissingCompileTimeError # Issue 19576
reify_typevar_static_test/00: MissingCompileTimeError # Issue 21565
+multiline_newline_test/01: CompileTimeError # Issue 23888
+multiline_newline_test/02: CompileTimeError # Issue 23888
+multiline_newline_test/03: CompileTimeError # Issue 23888
+multiline_newline_test/04: MissingCompileTimeError # Issue 23888
+multiline_newline_test/05: MissingCompileTimeError # Issue 23888
+multiline_newline_test/06: MissingCompileTimeError # Issue 23888
+
# Please add new failing tests before this line.
# Section below is for invalid tests.
#
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index b94754d..d6e6134 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -7,14 +7,15 @@
# Runtime negative test. No static errors or warnings.
closure_call_wrong_argument_count_negative_test: skip
-symbol_conflict_test: CompileTimeError # 23870
-
enum_syntax_test/02: Fail # 21649
enum_syntax_test/03: Fail # 21649
enum_syntax_test/04: Fail # 21649
enum_syntax_test/05: Fail # 21649
enum_syntax_test/06: Fail # 21649
+tearoff_basic_test: Skip # Tear-off not supported
+tearoff_constructor_basic_test: Skip # Tear-off not supported
+
regress_17382_test: Skip # don't care about the static warning.
regress_23408_test: Skip # don't care about the static warning.
getter_setter_in_lib_test: Fail # issue 23286
@@ -32,6 +33,13 @@
constructor_duplicate_final_test/03: Fail
reify_typevar_static_test/00: MissingCompileTimeError # Issue 21565
+multiline_newline_test/01: CompileTimeError # Issue 23888
+multiline_newline_test/02: CompileTimeError # Issue 23888
+multiline_newline_test/03: CompileTimeError # Issue 23888
+multiline_newline_test/04: MissingCompileTimeError # Issue 23888
+multiline_newline_test/05: MissingCompileTimeError # Issue 23888
+multiline_newline_test/06: MissingCompileTimeError # Issue 23888
+
# Please add new failing tests before this line.
# Section below is for invalid tests.
#
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index b6ce534..00d35b0 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -10,10 +10,70 @@
async_star_test/02: RuntimeError # 22853
async_star_test/05: RuntimeError, Timeout
+tearoff_basic_test: Skip # Tear-off not supported
+tearoff_constructor_basic_test: Skip # Tear-off not supported
try_catch_on_syntax_test/10: Fail # Issue 19823
try_catch_on_syntax_test/11: Fail # Issue 19823
+call_function_apply_test: RuntimeError # Issue 23873
+
+conditional_method_invocation_test/12: Fail # Issue 23795
+conditional_method_invocation_test/13: Fail # Issue 23795
+conditional_method_invocation_test/14: Fail # Issue 23795
+conditional_method_invocation_test/15: Fail # Issue 23795
+conditional_method_invocation_test/16: Fail # Issue 23795
+conditional_method_invocation_test/17: Fail # Issue 23795
+conditional_method_invocation_test/18: Fail # Issue 23795
+conditional_method_invocation_test/19: Fail # Issue 23795
+conditional_property_access_test/10: Fail # Issue 23795
+conditional_property_access_test/11: Fail # Issue 23795
+conditional_property_access_test/12: Fail # Issue 23795
+conditional_property_access_test/13: Fail # Issue 23795
+conditional_property_access_test/14: Fail # Issue 23795
+conditional_property_access_test/15: Fail # Issue 23795
+conditional_property_access_test/16: Fail # Issue 23795
+conditional_property_access_test/17: Fail # Issue 23795
+conditional_property_assignment_test/23: Fail # Issue 23795
+conditional_property_assignment_test/24: Fail # Issue 23795
+conditional_property_assignment_test/25: Fail # Issue 23795
+conditional_property_assignment_test/26: Fail # Issue 23795
+conditional_property_assignment_test/27: Fail # Issue 23795
+conditional_property_assignment_test/28: Fail # Issue 23795
+conditional_property_assignment_test/29: Fail # Issue 23795
+conditional_property_assignment_test/30: Fail # Issue 23795
+conditional_property_assignment_test/31: Fail # Issue 23795
+conditional_property_assignment_test/32: Fail # Issue 23795
+conditional_property_assignment_test/33: Fail # Issue 23795
+conditional_property_assignment_test/34: Fail # Issue 23795
+conditional_property_assignment_test/35: Fail # Issue 23795
+conditional_property_increment_decrement_test/17: Fail # Issue 23795
+conditional_property_increment_decrement_test/18: Fail # Issue 23795
+conditional_property_increment_decrement_test/19: Fail # Issue 23795
+conditional_property_increment_decrement_test/20: Fail # Issue 23795
+conditional_property_increment_decrement_test/21: Fail # Issue 23795
+conditional_property_increment_decrement_test/22: Fail # Issue 23795
+conditional_property_increment_decrement_test/23: Fail # Issue 23795
+conditional_property_increment_decrement_test/24: Fail # Issue 23795
+conditional_property_increment_decrement_test/25: Fail # Issue 23795
+conditional_property_increment_decrement_test/26: Fail # Issue 23795
+conditional_property_increment_decrement_test/27: Fail # Issue 23795
+conditional_property_increment_decrement_test/28: Fail # Issue 23795
+conditional_property_increment_decrement_test/29: Fail # Issue 23795
+conditional_property_increment_decrement_test/30: Fail # Issue 23795
+conditional_property_increment_decrement_test/31: Fail # Issue 23795
+conditional_property_increment_decrement_test/32: Fail # Issue 23795
+conditional_property_increment_decrement_test/33: Fail # Issue 23795
+conditional_property_increment_decrement_test/34: Fail # Issue 23795
+conditional_property_increment_decrement_test/35: Fail # Issue 23795
+conditional_property_increment_decrement_test/36: Fail # Issue 23795
+conditional_property_increment_decrement_test/37: Fail # Issue 23795
+conditional_property_increment_decrement_test/38: Fail # Issue 23795
+conditional_property_increment_decrement_test/39: Fail # Issue 23795
+conditional_property_increment_decrement_test/40: Fail # Issue 23795
+if_null_assignment_behavior_test/31: Fail # Issue 23795
+if_null_assignment_behavior_test/32: Fail # Issue 23795
+
[ $compiler == dart2js && $runtime == jsshell ]
await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
async_star_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
@@ -63,10 +123,8 @@
nullaware_opt_test: Fail # Fails at e?.f ??= 200;
if_null_assignment_behavior_test/29: Crash # Issue 23611
-if_null_assignment_behavior_test/30: Crash # Issue 23611
prefix_assignment_test/01: Crash # Issue 23611
prefix_assignment_test/02: Crash # Issue 23611
-prefix_identifier_reference_test/04: Crash # Issue 23611
prefix_identifier_reference_test/05: Crash # Issue 23611
const_error_multiply_initialized_test/02: CompileTimeError # Issue 23618
@@ -75,6 +133,14 @@
# VM specific tests that should not be run by dart2js.
vm/*: Skip # Issue 12699
+multiline_newline_test/01: CompileTimeError # Issue 23888
+multiline_newline_test/02: CompileTimeError # Issue 23888
+multiline_newline_test/03: CompileTimeError # Issue 23888
+multiline_newline_test/04: MissingCompileTimeError # Issue 23888
+multiline_newline_test/05: MissingCompileTimeError # Issue 23888
+multiline_newline_test/06: MissingCompileTimeError # Issue 23888
+multiline_newline_test/none: RuntimeError # Issue 23888
+
[ $compiler == dart2js && $checked ]
type_variable_bounds_test/02: Fail # Issue 12702
type_variable_bounds2_test/01: Fail # Issue 12702
@@ -233,6 +299,7 @@
[ $compiler == dart2js && $cps_ir == false ]
generic_field_mixin4_test: Crash # Issue 18651
generic_field_mixin5_test: Crash # Issue 18651
+many_method_calls_test: Crash # Stack overflow in HGraphVisitor.visitPostDominatorTree.visitBasicBlockAndSuccessors
[ $compiler == dart2js && $cps_ir ]
async_and_or_test: Crash # (test()async{await test1();await test2();}): cannot handle async/sync*/async* functions
@@ -351,9 +418,10 @@
cha_deopt3_test: Crash # (d.make_u()): deferred access is not implemented
closure_in_constructor_test: Crash # Invalid argument(s)
closure_type_variables_test: Crash # Invalid argument(s)
+closures_initializer_test: RuntimeError # Please triage this failure.
const_evaluation_test/01: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
constructor12_test: RuntimeError # Please triage this failure.
-crash_6725_test/01: Crash # The null object does not have a getter '_element'.
+crash_6725_test/01: Crash # unsupported operation on erroneous element
custom_await_stack_trace_test: Crash # (main()async{try {va... cannot handle async/sync*/async* functions
deferred_call_empty_before_load_test: Crash # (lib1.thefun()): deferred access is not implemented
deferred_closurize_load_library_test: Crash # (lib.trueVar): deferred access is not implemented
@@ -394,8 +462,13 @@
deferred_shadow_load_library_test: Crash # (lib.trueVar): deferred access is not implemented
deferred_shared_and_unshared_classes_test: Crash # (lib2.foo()): deferred access is not implemented
deferred_static_seperate_test: Crash # (lib1.x): deferred access is not implemented
+deferred_type_dependency_test/as: Crash # (main()async{await l... cannot handle async/sync*/async* functions
+deferred_type_dependency_test/is: Crash # (main()async{await l... cannot handle async/sync*/async* functions
+deferred_type_dependency_test/none: Crash # (main()async{await l... cannot handle async/sync*/async* functions
+deferred_type_dependency_test/type_annotation: Crash # (main()async{await l... cannot handle async/sync*/async* functions
enum_mirror_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
final_super_field_set_test/01: RuntimeError # Please triage this failure.
+first_class_types_test: RuntimeError # Please triage this failure.
flatten_test/01: Crash # (test()async{int x=await new Derived<int>();}): cannot handle async/sync*/async* functions
flatten_test/02: Crash # (test()async{Future<int> f()async=>new Derived<int>();}): cannot handle async/sync*/async* functions
flatten_test/03: Crash # (test()async{Future<... cannot handle async/sync*/async* functions
@@ -411,7 +484,10 @@
flatten_test/none: Crash # (test()async{}): cannot handle async/sync*/async* functions
for2_test: Crash # The null object does not have a getter 'field'.
for_variable_capture_test: Crash # (i=0): For-loop variable captured in loop header
+generic2_test: RuntimeError # Please triage this failure.
generic_field_mixin3_test: RuntimeError # Please triage this failure.
+generic_instanceof_test: RuntimeError # Please triage this failure.
+generic_native_test: RuntimeError # Please triage this failure.
if_null_assignment_behavior_test/12: RuntimeError # Please triage this failure.
if_null_assignment_behavior_test/28: RuntimeError # Please triage this failure.
if_null_assignment_static_test/01: RuntimeError # v0.get$a is not a function
@@ -428,17 +504,15 @@
if_null_assignment_static_test/40: RuntimeError # v0.get$a is not a function
infinite_switch_label_test: Crash # (switch (target){l0:... continue to a labeled switch case
instance_creation_in_function_annotation_test: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
+instanceof2_test: RuntimeError # Please triage this failure.
instanceof4_test/01: RuntimeError # Please triage this failure.
invocation_mirror_invoke_on_test: RuntimeError # Please triage this failure.
invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
issue_1751477_test: RuntimeError # O.loadLibrary is not a function
-large_class_declaration_test: Crash # Stack Overflow
+list_is_test: RuntimeError # Please triage this failure.
list_test: RuntimeError # Please triage this failure.
+many_generic_instanceof_test: RuntimeError # Please triage this failure.
many_overridden_no_such_method_test: RuntimeError # Please triage this failure.
-mixin_type_parameters_mixin_extends_test: Crash # The null object does not have a getter '_element'.
-mixin_type_parameters_mixin_test: Crash # The null object does not have a getter '_element'.
-mixin_type_parameters_super_extends_test: Crash # The null object does not have a getter '_element'.
-mixin_type_parameters_super_test: Crash # The null object does not have a getter '_element'.
nested_switch_label_test: Crash # (switch (target){out... continue to a labeled switch case
no_such_method_test: RuntimeError # Please triage this failure.
null_test/none: Crash # (static Iterable<Str... cannot handle async/sync*/async* functions
@@ -451,8 +525,6 @@
regress_22579_test: Crash # (main()async{var err... cannot handle async/sync*/async* functions
regress_22728_test: Crash # (main()async{bool fa... cannot handle async/sync*/async* functions
regress_22777_test: Crash # (test()async{try {te... cannot handle async/sync*/async* functions
-regress_22936_test/01: Crash # The null object does not have a getter '_element'.
-regress_22936_test/none: Crash # The null object does not have a getter '_element'.
regress_23408_test: RuntimeError # G.loadLibrary is not a function
regress_23498_test: Crash # (main()async{var err... cannot handle async/sync*/async* functions
regress_23500_test/01: Crash # (main()async{var err... cannot handle async/sync*/async* functions
@@ -483,7 +555,6 @@
syncstar_yield_test/copyParameters: Crash # (Iterable<int> foo3(... cannot handle async/sync*/async* functions
syncstar_yield_test/none: Crash # (Iterable<int> foo3(... cannot handle async/sync*/async* functions
syncstar_yieldstar_test: Crash # (main()async{Expect.... cannot handle async/sync*/async* functions
-try_catch_test/none: Crash # The null object does not have a getter '_element'.
type_parameter_test/01: Crash # Invalid argument(s)
type_parameter_test/02: Crash # Invalid argument(s)
type_parameter_test/03: Crash # Invalid argument(s)
@@ -493,3 +564,9 @@
type_parameter_test/none: Crash # Invalid argument(s)
type_variable_closure2_test: RuntimeError # Please triage this failure.
type_variable_closure_test: Crash # Invalid argument(s)
+type_variable_field_initializer_closure_test: RuntimeError # Please triage this failure.
+type_variable_field_initializer_test: RuntimeError # Please triage this failure.
+type_variable_nested_test: RuntimeError # Please triage this failure.
+
+[ $compiler == dart2js && ($runtime == d8 || $runtime == jsshell) ]
+issue23244_test: RuntimeError # 23244
diff --git a/tests/language/larger_implicit_getter_test.dart b/tests/language/larger_implicit_getter_test.dart
new file mode 100644
index 0000000..31c5969
--- /dev/null
+++ b/tests/language/larger_implicit_getter_test.dart
@@ -0,0 +1,4100 @@
+// 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.
+// Dart test program for testing compilation of large implicit getters.
+
+import 'package:expect/expect.dart';
+
+List<List> panels = [
+ [6853.940039224797,6050.837897021371],
+ [6953.240039224797,6050.837897021371],
+ [7052.5400392247975,5885.237897021371],
+ [7052.5400392247975,5719.637897021372],
+ [7151.840039224798,5885.237897021371],
+ [7052.5400392247975,6050.837897021371],
+ [7052.5400392247975,6216.43789702137],
+ [7052.5400392247975,6382.03789702137],
+ [6953.240039224797,6382.03789702137],
+ [6953.240039224797,6216.43789702137],
+ [6853.940039224797,6216.43789702137],
+ [6853.940039224797,6382.03789702137],
+ [6754.640039224797,6216.43789702137],
+ [6754.640039224797,6382.03789702137],
+ [6754.640039224797,6547.637897021369],
+ [6754.640039224797,6713.237897021369],
+ [6655.340039224797,6713.237897021369],
+ [6754.640039224797,6878.837897021368],
+ [6853.940039224797,6713.237897021369],
+ [6853.940039224797,6878.837897021368],
+ [6953.240039224797,6713.237897021369],
+ [7052.5400392247975,6547.637897021369],
+ [7151.840039224798,6713.237897021369],
+ [7151.840039224798,6547.637897021369],
+ [7151.840039224798,6382.03789702137],
+ [7251.140039224798,6547.637897021369],
+ [7251.140039224798,6713.237897021369],
+ [7350.440039224798,6878.837897021368],
+ [7449.740039224798,6878.837897021368],
+ [7449.740039224798,6713.237897021369],
+ [7549.040039224798,6547.637897021369],
+ [7449.740039224798,6382.03789702137],
+ [7449.740039224798,6216.43789702137],
+ [7549.040039224798,6050.837897021371],
+ [7648.340039224799,6216.43789702137],
+ [7549.040039224798,6382.03789702137],
+ [7648.340039224799,6382.03789702137],
+ [7747.640039224799,6216.43789702137],
+ [7846.940039224799,6382.03789702137],
+ [7946.240039224799,6382.03789702137],
+ [7946.240039224799,6547.637897021369],
+ [7846.940039224799,6713.237897021369],
+ [7946.240039224799,6713.237897021369],
+ [8045.540039224799,6547.637897021369],
+ [8045.540039224799,6713.237897021369],
+ [7946.240039224799,6878.837897021368],
+ [7946.240039224799,7044.4378970213675],
+ [8045.540039224799,7210.037897021367],
+ [8144.8400392247995,7375.637897021366],
+ [8144.8400392247995,7541.237897021366],
+ [8045.540039224799,7375.637897021366],
+ [8144.8400392247995,7210.037897021367],
+ [8045.540039224799,7044.4378970213675],
+ [7946.240039224799,7210.037897021367],
+ [7846.940039224799,7210.037897021367],
+ [7946.240039224799,7375.637897021366],
+ [8045.540039224799,7541.237897021366],
+ [8144.8400392247995,7706.837897021365],
+ [8244.1400392248,7541.237897021366],
+ [8343.4400392248,7541.237897021366],
+ [8343.4400392248,7706.837897021365],
+ [8244.1400392248,7706.837897021365],
+ [4735.523842661975,3503.497768214323],
+ [4636.223842661975,3337.897768214323],
+ [4536.923842661975,3337.897768214323],
+ [4437.623842661975,3172.2977682143232],
+ [4338.323842661975,3172.2977682143232],
+ [4239.023842661974,3172.2977682143232],
+ [4338.323842661975,3006.6977682143233],
+ [4437.623842661975,2841.0977682143234],
+ [4338.323842661975,2675.4977682143235],
+ [4338.323842661975,2509.8977682143236],
+ [4239.023842661974,2675.4977682143235],
+ [4139.723842661974,2509.8977682143236],
+ [4040.4238426619745,2344.2977682143237],
+ [4139.723842661974,2178.697768214324],
+ [4239.023842661974,2178.697768214324],
+ [4139.723842661974,2344.2977682143237],
+ [4040.4238426619745,2178.697768214324],
+ [4139.723842661974,2013.0977682143237],
+ [4139.723842661974,1847.4977682143235],
+ [4239.023842661974,2013.0977682143237],
+ [4239.023842661974,1847.4977682143235],
+ [4338.323842661975,1847.4977682143235],
+ [4437.623842661975,1847.4977682143235],
+ [4536.923842661975,1681.8977682143234],
+ [4437.623842661975,1516.2977682143232],
+ [4536.923842661975,1516.2977682143232],
+ [4536.923842661975,1350.697768214323],
+ [4437.623842661975,1350.697768214323],
+ [4536.923842661975,1185.097768214323],
+ [4636.223842661975,1019.497768214323],
+ [4536.923842661975,853.897768214323],
+ [4636.223842661975,853.897768214323],
+ [4735.523842661975,688.2977682143231],
+ [4636.223842661975,522.6977682143232],
+ [4636.223842661975,357.09776821432325],
+ [4735.523842661975,357.09776821432325],
+ [4735.523842661975,522.6977682143232],
+ [4636.223842661975,688.2977682143231],
+ [4735.523842661975,853.897768214323],
+ [4834.8238426619755,853.897768214323],
+ [4735.523842661975,1019.497768214323],
+ [4735.523842661975,1185.097768214323],
+ [4735.523842661975,1350.697768214323],
+ [4834.8238426619755,1516.2977682143232],
+ [4735.523842661975,1516.2977682143232],
+ [4834.8238426619755,1350.697768214323],
+ [4834.8238426619755,1185.097768214323],
+ [4934.123842661976,1350.697768214323],
+ [5033.423842661976,1185.097768214323],
+ [5033.423842661976,1019.497768214323],
+ [5033.423842661976,853.897768214323],
+ [4934.123842661976,853.897768214323],
+ [4934.123842661976,1019.497768214323],
+ [4834.8238426619755,1019.497768214323],
+ [4934.123842661976,1185.097768214323],
+ [5033.423842661976,1350.697768214323],
+ [5132.723842661976,1350.697768214323],
+ [5132.723842661976,1185.097768214323],
+ [5232.023842661976,1019.497768214323],
+ [5232.023842661976,1185.097768214323],
+ [5331.323842661976,1019.497768214323],
+ [5430.623842661977,1019.497768214323],
+ [5529.923842661977,1185.097768214323],
+ [5430.623842661977,1350.697768214323],
+ [5430.623842661977,1516.2977682143232],
+ [5529.923842661977,1350.697768214323],
+ [5629.223842661977,1350.697768214323],
+ [5728.523842661977,1350.697768214323],
+ [5728.523842661977,1516.2977682143232],
+ [5728.523842661977,1681.8977682143234],
+ [5629.223842661977,1516.2977682143232],
+ [5529.923842661977,1516.2977682143232],
+ [5629.223842661977,1681.8977682143234],
+ [5529.923842661977,1681.8977682143234],
+ [5430.623842661977,1847.4977682143235],
+ [5331.323842661976,1847.4977682143235],
+ [5331.323842661976,2013.0977682143237],
+ [5232.023842661976,2178.697768214324],
+ [5132.723842661976,2013.0977682143237],
+ [5132.723842661976,2178.697768214324],
+ [5232.023842661976,2013.0977682143237],
+ [5232.023842661976,1847.4977682143235],
+ [5232.023842661976,1681.8977682143234],
+ [5331.323842661976,1681.8977682143234],
+ [5331.323842661976,1516.2977682143232],
+ [5331.323842661976,1350.697768214323],
+ [5232.023842661976,1350.697768214323],
+ [5232.023842661976,1516.2977682143232],
+ [5132.723842661976,1516.2977682143232],
+ [5132.723842661976,1681.8977682143234],
+ [5033.423842661976,1847.4977682143235],
+ [5132.723842661976,1847.4977682143235],
+ [5033.423842661976,2013.0977682143237],
+ [4934.123842661976,2178.697768214324],
+ [5033.423842661976,2344.2977682143237],
+ [4934.123842661976,2344.2977682143237],
+ [4834.8238426619755,2178.697768214324],
+ [4834.8238426619755,2344.2977682143237],
+ [4735.523842661975,2344.2977682143237],
+ [4636.223842661975,2344.2977682143237],
+ [4536.923842661975,2178.697768214324],
+ [4437.623842661975,2013.0977682143237],
+ [4338.323842661975,2178.697768214324],
+ [4437.623842661975,2344.2977682143237],
+ [4536.923842661975,2509.8977682143236],
+ [4636.223842661975,2675.4977682143235],
+ [4636.223842661975,2509.8977682143236],
+ [4536.923842661975,2675.4977682143235],
+ [4636.223842661975,2841.0977682143234],
+ [4536.923842661975,2841.0977682143234],
+ [4636.223842661975,3006.6977682143233],
+ [4735.523842661975,3172.2977682143232],
+ [4834.8238426619755,3006.6977682143233],
+ [4735.523842661975,2841.0977682143234],
+ [4735.523842661975,3006.6977682143233],
+ [4636.223842661975,3172.2977682143232],
+ [4735.523842661975,3337.897768214323],
+ [4834.8238426619755,3503.497768214323],
+ [4735.523842661975,3669.097768214323],
+ [4834.8238426619755,3834.697768214323],
+ [4834.8238426619755,3669.097768214323],
+ [4934.123842661976,3503.497768214323],
+ [5033.423842661976,3503.497768214323],
+ [5033.423842661976,3337.897768214323],
+ [4934.123842661976,3337.897768214323],
+ [4834.8238426619755,3172.2977682143232],
+ [4834.8238426619755,3337.897768214323],
+ [4934.123842661976,3172.2977682143232],
+ [5033.423842661976,3006.6977682143233],
+ [5132.723842661976,2841.0977682143234],
+ [5132.723842661976,3006.6977682143233],
+ [5232.023842661976,3172.2977682143232],
+ [5232.023842661976,3337.897768214323],
+ [5132.723842661976,3337.897768214323],
+ [5232.023842661976,3503.497768214323],
+ [5331.323842661976,3337.897768214323],
+ [5331.323842661976,3503.497768214323],
+ [5430.623842661977,3669.097768214323],
+ [5331.323842661976,3669.097768214323],
+ [5430.623842661977,3503.497768214323],
+ [5430.623842661977,3337.897768214323],
+ [5529.923842661977,3172.2977682143232],
+ [5529.923842661977,3337.897768214323],
+ [5629.223842661977,3337.897768214323],
+ [5728.523842661977,3337.897768214323],
+ [5728.523842661977,3503.497768214323],
+ [5827.823842661977,3503.497768214323],
+ [5927.1238426619775,3669.097768214323],
+ [6026.423842661978,3669.097768214323],
+ [6125.723842661978,3503.497768214323],
+ [6125.723842661978,3669.097768214323],
+ [6225.023842661978,3503.497768214323],
+ [6225.023842661978,3337.897768214323],
+ [6324.323842661978,3337.897768214323],
+ [6423.623842661978,3503.497768214323],
+ [6324.323842661978,3669.097768214323],
+ [6225.023842661978,3669.097768214323],
+ [6324.323842661978,3834.697768214323],
+ [6423.623842661978,3834.697768214323],
+ [6324.323842661978,4000.297768214323],
+ [6225.023842661978,3834.697768214323],
+ [6125.723842661978,3834.697768214323],
+ [6125.723842661978,4000.297768214323],
+ [6225.023842661978,4000.297768214323],
+ [6225.023842661978,4165.897768214322],
+ [6225.023842661978,4331.497768214322],
+ [6125.723842661978,4165.897768214322],
+ [6026.423842661978,4000.2977682143223],
+ [5927.1238426619775,4165.897768214322],
+ [6026.423842661978,4331.497768214322],
+ [6026.423842661978,4497.097768214321],
+ [5927.1238426619775,4497.097768214321],
+ [5827.823842661977,4662.697768214321],
+ [5728.523842661977,4828.29776821432],
+ [5827.823842661977,4828.29776821432],
+ [5927.1238426619775,4828.29776821432],
+ [5927.1238426619775,4662.697768214321],
+ [5827.823842661977,4497.097768214321],
+ [5927.1238426619775,4331.497768214322],
+ [5827.823842661977,4165.897768214322],
+ [5728.523842661977,4331.497768214322],
+ [5728.523842661977,4165.897768214322],
+ [5629.223842661977,4000.2977682143223],
+ [5629.223842661977,3834.6977682143224],
+ [5529.923842661977,3669.0977682143225],
+ [5629.223842661977,3503.4977682143226],
+ [5728.523842661977,3669.0977682143225],
+ [5827.823842661977,3669.0977682143225],
+ [5927.1238426619775,3834.6977682143224],
+ [5927.1238426619775,4000.2977682143223],
+ [6026.423842661978,4165.897768214322],
+ [6125.723842661978,4331.497768214322],
+ [6225.023842661978,4497.097768214321],
+ [6225.023842661978,4662.697768214321],
+ [6324.323842661978,4662.697768214321],
+ [6225.023842661978,4828.29776821432],
+ [6324.323842661978,4828.29776821432],
+ [6423.623842661978,4828.29776821432],
+ [6324.323842661978,4993.8977682143195],
+ [6225.023842661978,5159.497768214319],
+ [6125.723842661978,5159.497768214319],
+ [6026.423842661978,5325.097768214318],
+ [5927.1238426619775,5490.697768214318],
+ [6026.423842661978,5656.297768214317],
+ [5927.1238426619775,5821.897768214317],
+ [5927.1238426619775,5987.497768214316],
+ [6026.423842661978,5987.497768214316],
+ [6026.423842661978,5821.897768214317],
+ [5927.1238426619775,5656.297768214317],
+ [5827.823842661977,5656.297768214317],
+ [5827.823842661977,5490.697768214318],
+ [5728.523842661977,5490.697768214318],
+ [5629.223842661977,5325.097768214318],
+ [5629.223842661977,5159.497768214319],
+ [5529.923842661977,4993.8977682143195],
+ [5529.923842661977,5159.497768214319],
+ [5629.223842661977,4993.8977682143195],
+ [5629.223842661977,4828.29776821432],
+ [5529.923842661977,4662.697768214321],
+ [5430.623842661977,4828.29776821432],
+ [5529.923842661977,4828.29776821432],
+ [5629.223842661977,4662.697768214321],
+ [5728.523842661977,4662.697768214321],
+ [5629.223842661977,4497.097768214321],
+ [5728.523842661977,4497.097768214321],
+ [5827.823842661977,4331.497768214322],
+ [10216.161365168813,2951.605409896135],
+ [10116.861365168812,2951.605409896135],
+ [10017.56136516881,3117.205409896135],
+ [9918.26136516881,3117.205409896135],
+ [9818.961365168809,3117.205409896135],
+ [9719.661365168808,3282.8054098961347],
+ [9620.361365168807,3282.8054098961347],
+ [9620.361365168807,3117.205409896135],
+ [9521.061365168805,2951.605409896135],
+ [9521.061365168805,2786.005409896135],
+ [9620.361365168807,2786.005409896135],
+ [9719.661365168808,2786.005409896135],
+ [9818.961365168809,2620.405409896135],
+ [9918.26136516881,2786.005409896135],
+ [9818.961365168809,2951.605409896135],
+ [9818.961365168809,2786.005409896135],
+ [9719.661365168808,2620.405409896135],
+ [9719.661365168808,2454.805409896135],
+ [9620.361365168807,2289.2054098961353],
+ [9521.061365168805,2123.6054098961354],
+ [9620.361365168807,1958.0054098961352],
+ [9719.661365168808,2123.6054098961354],
+ [9818.961365168809,2289.2054098961353],
+ [9818.961365168809,2123.6054098961354],
+ [9818.961365168809,1958.0054098961352],
+ [9719.661365168808,1958.0054098961352],
+ [9620.361365168807,1792.405409896135],
+ [9620.361365168807,1626.805409896135],
+ [9521.061365168805,1461.2054098961348],
+ [9421.761365168804,1295.6054098961347],
+ [9521.061365168805,1130.0054098961346],
+ [9521.061365168805,964.4054098961345],
+ [9421.761365168804,964.4054098961345],
+ [9521.061365168805,798.8054098961346],
+ [9620.361365168807,798.8054098961346],
+ [9620.361365168807,964.4054098961345],
+ [9620.361365168807,1130.0054098961346],
+ [9620.361365168807,1295.6054098961347],
+ [9620.361365168807,1461.2054098961348],
+ [9719.661365168808,1295.6054098961347],
+ [9818.961365168809,1130.0054098961346],
+ [9918.26136516881,964.4054098961345],
+ [9818.961365168809,964.4054098961345],
+ [9918.26136516881,798.8054098961346],
+ [10017.56136516881,633.2054098961347],
+ [9918.26136516881,467.60540989613474],
+ [9918.26136516881,302.0054098961348],
+ [10017.56136516881,302.0054098961348],
+ [10116.861365168812,136.40540989613478],
+ [10116.861365168812,302.0054098961348],
+ [10116.861365168812,467.60540989613474],
+ [10116.861365168812,633.2054098961347],
+ [10216.161365168813,633.2054098961347],
+ [10216.161365168813,798.8054098961346],
+ [10315.461365168814,633.2054098961347],
+ [10315.461365168814,798.8054098961346],
+ [10414.761365168815,798.8054098961346],
+ [10514.061365168816,633.2054098961347],
+ [10514.061365168816,798.8054098961346],
+ [10414.761365168815,964.4054098961345],
+ [10315.461365168814,964.4054098961345],
+ [10216.161365168813,964.4054098961345],
+ [10116.861365168812,798.8054098961346],
+ [10017.56136516881,798.8054098961346],
+ [10116.861365168812,964.4054098961345],
+ [10216.161365168813,1130.0054098961346],
+ [10116.861365168812,1130.0054098961346],
+ [10216.161365168813,1295.6054098961347],
+ [10216.161365168813,1461.2054098961348],
+ [10315.461365168814,1626.805409896135],
+ [10315.461365168814,1792.405409896135],
+ [10216.161365168813,1958.0054098961352],
+ [10216.161365168813,1792.405409896135],
+ [10116.861365168812,1792.405409896135],
+ [10017.56136516881,1958.0054098961352],
+ [9918.26136516881,2123.6054098961354],
+ [9918.26136516881,1958.0054098961352],
+ [10017.56136516881,2123.6054098961354],
+ [10116.861365168812,2123.6054098961354],
+ [10017.56136516881,2289.2054098961353],
+ [10017.56136516881,2454.805409896135],
+ [10116.861365168812,2289.2054098961353],
+ [10216.161365168813,2454.805409896135],
+ [10315.461365168814,2620.405409896135],
+ [10315.461365168814,2454.805409896135],
+ [10315.461365168814,2289.2054098961353],
+ [10414.761365168815,2454.805409896135],
+ [10514.061365168816,2620.405409896135],
+ [10613.361365168817,2786.005409896135],
+ [10514.061365168816,2786.005409896135],
+ [10613.361365168817,2620.405409896135],
+ [10514.061365168816,2454.805409896135],
+ [10514.061365168816,2289.2054098961353],
+ [10613.361365168817,2289.2054098961353],
+ [10712.661365168819,2289.2054098961353],
+ [10811.96136516882,2454.805409896135],
+ [10911.26136516882,2289.2054098961353],
+ [10811.96136516882,2289.2054098961353],
+ [10712.661365168819,2454.805409896135],
+ [10712.661365168819,2620.405409896135],
+ [10811.96136516882,2786.005409896135],
+ [10911.26136516882,2620.405409896135],
+ [10911.26136516882,2786.005409896135],
+ [11010.561365168822,2620.405409896135],
+ [10911.26136516882,2454.805409896135],
+ [10811.96136516882,2620.405409896135],
+ [10712.661365168819,2786.005409896135],
+ [10811.96136516882,2951.605409896135],
+ [10911.26136516882,2951.605409896135],
+ [10811.96136516882,3117.205409896135],
+ [10712.661365168819,2951.605409896135],
+ [10613.361365168817,2951.605409896135],
+ [10514.061365168816,2951.605409896135],
+ [10414.761365168815,3117.205409896135],
+ [10414.761365168815,2951.605409896135],
+ [10315.461365168814,2786.005409896135],
+ [10216.161365168813,2620.405409896135],
+ [10216.161365168813,2786.005409896135],
+ [10315.461365168814,2951.605409896135],
+ [10315.461365168814,3117.205409896135],
+ [10216.161365168813,3117.205409896135],
+ [10116.861365168812,3117.205409896135],
+ [10017.56136516881,3282.8054098961347],
+ [9918.26136516881,3448.4054098961346],
+ [9818.961365168809,3448.4054098961346],
+ [9818.961365168809,3614.0054098961346],
+ [9719.661365168808,3448.4054098961346],
+ [9818.961365168809,3282.8054098961347],
+ [9719.661365168808,3117.205409896135],
+ [9620.361365168807,2951.605409896135],
+ [9521.061365168805,3117.205409896135],
+ [9521.061365168805,3282.8054098961347],
+ [9421.761365168804,3117.205409896135],
+ [9421.761365168804,3282.8054098961347],
+ [9322.461365168803,3117.205409896135],
+ [9421.761365168804,2951.605409896135],
+ [9322.461365168803,2951.605409896135],
+ [9223.161365168802,2786.005409896135],
+ [9322.461365168803,2620.405409896135],
+ [9421.761365168804,2454.805409896135],
+ [9521.061365168805,2289.2054098961353],
+ [9421.761365168804,2123.6054098961354],
+ [9421.761365168804,1958.0054098961352],
+ [9421.761365168804,1792.405409896135],
+ [9521.061365168805,1626.805409896135],
+ [9421.761365168804,1626.805409896135],
+ [9322.461365168803,1792.405409896135],
+ [9322.461365168803,1626.805409896135],
+ [9322.461365168803,1461.2054098961348],
+ [9421.761365168804,1461.2054098961348],
+ [9521.061365168805,1295.6054098961347],
+ [9421.761365168804,1130.0054098961346],
+ [9322.461365168803,964.4054098961345],
+ [9223.161365168802,964.4054098961345],
+ [9223.161365168802,798.8054098961346],
+ [9322.461365168803,633.2054098961347],
+ [9421.761365168804,798.8054098961346],
+ [9421.761365168804,633.2054098961347],
+ [9521.061365168805,633.2054098961347],
+ [9421.761365168804,467.60540989613474],
+ [9421.761365168804,302.0054098961348],
+ [9322.461365168803,136.40540989613478],
+ [9223.161365168802,302.0054098961348],
+ [9123.861365168801,302.0054098961348],
+ [9024.5613651688,136.40540989613478],
+ [9123.861365168801,136.40540989613478],
+ [9223.161365168802,136.40540989613478],
+ [9322.461365168803,302.0054098961348],
+ [9421.761365168804,136.40540989613478],
+ [9521.061365168805,136.40540989613478],
+ [9620.361365168807,136.40540989613478],
+ [9620.361365168807,302.0054098961348],
+ [9521.061365168805,302.0054098961348],
+ [9521.061365168805,467.60540989613474],
+ [9620.361365168807,467.60540989613474],
+ [9719.661365168808,302.0054098961348],
+ [9719.661365168808,136.40540989613478],
+ [9818.961365168809,136.40540989613478],
+ [9918.26136516881,136.40540989613478],
+ [10017.56136516881,136.40540989613478],
+ [366.07287160549004,5394.185440937868],
+ [465.37287160549005,5394.185440937868],
+ [465.37287160549005,5559.785440937868],
+ [366.0728716054901,5559.785440937868],
+ [366.0728716054901,5725.385440937867],
+ [266.77287160549014,5725.385440937867],
+ [167.47287160549016,5559.785440937868],
+ [266.77287160549014,5559.785440937868],
+ [266.77287160549014,5394.185440937868],
+ [266.77287160549014,5228.585440937869],
+ [167.47287160549016,5394.185440937868],
+ [68.17287160549016,5228.585440937869],
+ [167.47287160549013,5062.9854409378695],
+ [68.17287160549013,4897.38544093787],
+ [167.47287160549013,4731.785440937871],
+ [266.77287160549014,4731.785440937871],
+ [167.47287160549016,4566.185440937871],
+ [68.17287160549016,4566.185440937871],
+ [68.17287160549016,4731.785440937871],
+ [167.47287160549013,4897.38544093787],
+ [68.17287160549013,5062.9854409378695],
+ [167.47287160549013,5228.585440937869],
+ [266.77287160549014,5062.9854409378695],
+ [366.0728716054901,4897.38544093787],
+ [266.77287160549014,4897.38544093787],
+ [366.0728716054901,4731.785440937871],
+ [465.37287160549005,4897.38544093787],
+ [366.0728716054901,5062.9854409378695],
+ [465.37287160549005,5062.9854409378695],
+ [366.0728716054901,5228.585440937869],
+ [465.37287160549005,5228.585440937869],
+ [564.6728716054901,5394.185440937868],
+ [663.9728716054901,5228.585440937869],
+ [564.6728716054901,5062.9854409378695],
+ [663.9728716054901,4897.38544093787],
+ [763.2728716054902,4731.785440937871],
+ [862.5728716054903,4566.185440937871],
+ [961.8728716054903,4731.785440937871],
+ [862.5728716054903,4731.785440937871],
+ [961.8728716054903,4566.185440937871],
+ [862.5728716054903,4400.585440937872],
+ [961.8728716054903,4234.985440937872],
+ [1061.1728716054904,4400.585440937872],
+ [1160.4728716054904,4234.985440937872],
+ [1160.4728716054904,4400.585440937872],
+ [1259.7728716054903,4234.985440937872],
+ [1359.0728716054903,4069.3854409378723],
+ [1458.3728716054902,4069.3854409378723],
+ [1557.6728716054902,4234.985440937872],
+ [1656.9728716054901,4400.585440937872],
+ [1557.6728716054902,4400.585440937872],
+ [1458.3728716054902,4400.585440937872],
+ [1359.0728716054903,4566.185440937871],
+ [1359.0728716054903,4731.785440937871],
+ [1259.7728716054903,4731.785440937871],
+ [1359.0728716054903,4897.38544093787],
+ [1458.3728716054902,4731.785440937871],
+ [1458.3728716054902,4897.38544093787],
+ [1359.0728716054903,5062.9854409378695],
+ [1259.7728716054903,5228.585440937869],
+ [1259.7728716054903,5062.9854409378695],
+ [1259.7728716054903,4897.38544093787],
+ [1160.4728716054904,5062.9854409378695],
+ [1160.4728716054904,5228.585440937869],
+ [1061.1728716054904,5228.585440937869],
+ [1061.1728716054904,5062.9854409378695],
+ [961.8728716054903,5228.585440937869],
+ [862.5728716054903,5062.9854409378695],
+ [961.8728716054903,5062.9854409378695],
+ [961.8728716054903,4897.38544093787],
+ [1061.1728716054904,4897.38544093787],
+ [1160.4728716054904,4731.785440937871],
+ [1259.7728716054903,4566.185440937871],
+ [1359.0728716054903,4400.585440937872],
+ [1458.3728716054902,4566.185440937871],
+ [1557.6728716054902,4566.185440937871],
+ [1656.9728716054901,4731.785440937871],
+ [1557.6728716054902,4897.38544093787],
+ [1458.3728716054902,5062.9854409378695],
+ [1557.6728716054902,5228.585440937869],
+ [1656.9728716054901,5062.9854409378695],
+ [1756.27287160549,5062.9854409378695],
+ [1756.27287160549,4897.38544093787],
+ [1855.57287160549,5062.9854409378695],
+ [1954.87287160549,4897.38544093787],
+ [2054.17287160549,5062.9854409378695],
+ [1954.87287160549,5062.9854409378695],
+ [2054.17287160549,5228.585440937869],
+ [2153.4728716054897,5228.585440937869],
+ [2252.7728716054894,5062.9854409378695],
+ [2352.072871605489,5228.585440937869],
+ [2451.372871605489,5394.185440937868],
+ [2352.072871605489,5394.185440937868],
+ [2252.7728716054894,5228.585440937869],
+ [2153.4728716054897,5062.9854409378695],
+ [2153.4728716054897,4897.38544093787],
+ [2252.7728716054894,4897.38544093787],
+ [2352.072871605489,4731.785440937871],
+ [2252.7728716054894,4731.785440937871],
+ [2153.4728716054897,4731.785440937871],
+ [2054.17287160549,4566.185440937871],
+ [1954.87287160549,4731.785440937871],
+ [1855.57287160549,4897.38544093787],
+ [1756.27287160549,4731.785440937871],
+ [1855.57287160549,4731.785440937871],
+ [1855.57287160549,4566.185440937871],
+ [1756.27287160549,4566.185440937871],
+ [1656.9728716054901,4566.185440937871],
+ [1557.6728716054902,4731.785440937871],
+ [1656.9728716054901,4897.38544093787],
+ [1557.6728716054902,5062.9854409378695],
+ [1458.3728716054902,5228.585440937869],
+ [1359.0728716054903,5228.585440937869],
+ [1259.7728716054903,5394.185440937868],
+ [1259.7728716054903,5559.785440937868],
+ [1160.4728716054904,5559.785440937868],
+ [1061.1728716054904,5559.785440937868],
+ [1160.4728716054904,5725.385440937867],
+ [1259.7728716054903,5725.385440937867],
+ [1359.0728716054903,5559.785440937868],
+ [1458.3728716054902,5725.385440937867],
+ [1458.3728716054902,5559.785440937868],
+ [1359.0728716054903,5725.385440937867],
+ [1259.7728716054903,5890.985440937867],
+ [1359.0728716054903,5890.985440937867],
+ [1259.7728716054903,6056.585440937866],
+ [1359.0728716054903,6222.185440937866],
+ [1458.3728716054902,6222.185440937866],
+ [1458.3728716054902,6387.785440937865],
+ [1557.6728716054902,6222.185440937866],
+ [1557.6728716054902,6387.785440937865],
+ [1656.9728716054901,6222.185440937866],
+ [1756.27287160549,6056.585440937866],
+ [1855.57287160549,5890.985440937867],
+ [1756.27287160549,5890.985440937867],
+ [1656.9728716054901,6056.585440937866],
+ [1557.6728716054902,5890.985440937867],
+ [1458.3728716054902,5890.985440937867],
+ [1359.0728716054903,6056.585440937866],
+ [1259.7728716054903,6222.185440937866],
+ [1160.4728716054904,6056.585440937866],
+ [1061.1728716054904,5890.985440937867],
+ [1061.1728716054904,6056.585440937866],
+ [1160.4728716054904,6222.185440937866],
+ [1061.1728716054904,6222.185440937866],
+ [961.8728716054903,6222.185440937866],
+ [961.8728716054903,6056.585440937866],
+ [961.8728716054903,5890.985440937867],
+ [961.8728716054903,5725.385440937867],
+ [862.5728716054903,5559.785440937868],
+ [763.2728716054902,5725.385440937867],
+ [862.5728716054903,5725.385440937867],
+ [763.2728716054902,5890.985440937867],
+ [663.9728716054901,5725.385440937867],
+ [763.2728716054902,5559.785440937868],
+ [763.2728716054902,5394.185440937868],
+ [862.5728716054903,5228.585440937869],
+ [961.8728716054903,5394.185440937868],
+ [1061.1728716054904,5394.185440937868],
+ [961.8728716054903,5559.785440937868],
+ [862.5728716054903,5394.185440937868],
+ [763.2728716054902,5228.585440937869],
+ [663.9728716054901,5062.9854409378695],
+ [763.2728716054902,5062.9854409378695],
+ [763.2728716054902,4897.38544093787],
+ [663.9728716054901,4731.785440937871],
+ [564.6728716054901,4731.785440937871],
+ [465.37287160549005,4566.185440937871],
+ [366.0728716054901,4566.185440937871],
+ [465.37287160549005,4731.785440937871],
+ [564.6728716054901,4566.185440937871],
+ [465.37287160549005,4400.585440937872],
+ [366.0728716054901,4400.585440937872],
+ [266.77287160549014,4234.985440937872],
+ [167.47287160549016,4234.985440937872],
+ [266.77287160549014,4400.585440937872],
+ [266.77287160549014,4566.185440937871],
+ [167.47287160549016,4400.585440937872],
+ [68.17287160549016,4234.985440937872],
+ [167.47287160549013,4069.3854409378723],
+ [68.17287160549013,3903.7854409378724],
+ [68.17287160549013,4069.3854409378723],
+ [167.47287160549013,3903.7854409378724],
+ [266.77287160549014,3903.7854409378724],
+ [366.0728716054901,3738.1854409378725],
+ [266.77287160549014,3738.1854409378725],
+ [266.77287160549014,3572.5854409378726],
+ [167.47287160549016,3406.9854409378727],
+ [167.47287160549016,3241.3854409378728],
+ [266.77287160549014,3241.3854409378728],
+ [266.77287160549014,3406.9854409378727],
+ [366.0728716054901,3572.5854409378726],
+ [465.37287160549005,3738.1854409378725],
+ [465.37287160549005,3903.7854409378724],
+ [366.0728716054901,4069.3854409378723],
+ [366.0728716054901,4234.985440937872],
+ [465.37287160549005,4234.985440937872],
+ [564.6728716054901,4069.3854409378723],
+ [465.37287160549005,4069.3854409378723],
+ [564.6728716054901,4234.985440937872],
+ [663.9728716054901,4069.3854409378723],
+ [663.9728716054901,4234.985440937872],
+ [663.9728716054901,4400.585440937872],
+ [763.2728716054902,4566.185440937871],
+ [763.2728716054902,4400.585440937872],
+ [663.9728716054901,4566.185440937871],
+ [564.6728716054901,4400.585440937872],
+ [19431.915041401327,3495.506142643713],
+ [19332.61504140133,3661.1061426437127],
+ [19431.915041401327,3661.1061426437127],
+ [19531.215041401327,3661.1061426437127],
+ [19630.515041401326,3495.506142643713],
+ [19630.515041401326,3661.1061426437127],
+ [19729.815041401325,3826.7061426437126],
+ [19630.515041401326,3826.7061426437126],
+ [19729.815041401325,3992.3061426437125],
+ [19630.515041401326,3992.3061426437125],
+ [19630.515041401326,4157.906142643712],
+ [19630.515041401326,4323.506142643711],
+ [19531.215041401327,4157.906142643712],
+ [19431.915041401327,4323.506142643711],
+ [19531.215041401327,4489.106142643711],
+ [19431.915041401327,4654.70614264371],
+ [19332.61504140133,4654.70614264371],
+ [19332.61504140133,4820.30614264371],
+ [19332.61504140133,4985.906142643709],
+ [19233.31504140133,4985.906142643709],
+ [19134.01504140133,5151.506142643709],
+ [19034.71504140133,5151.506142643709],
+ [19134.01504140133,5317.106142643708],
+ [19034.71504140133,5317.106142643708],
+ [19034.71504140133,5482.706142643708],
+ [18935.41504140133,5648.306142643707],
+ [18836.115041401332,5813.9061426437065],
+ [18836.115041401332,5979.506142643706],
+ [18935.41504140133,5979.506142643706],
+ [19034.71504140133,6145.106142643705],
+ [19034.71504140133,5979.506142643706],
+ [19034.71504140133,5813.9061426437065],
+ [19134.01504140133,5648.306142643707],
+ [19233.31504140133,5648.306142643707],
+ [19134.01504140133,5813.9061426437065],
+ [19134.01504140133,5979.506142643706],
+ [19233.31504140133,5813.9061426437065],
+ [19233.31504140133,5979.506142643706],
+ [19332.61504140133,6145.106142643705],
+ [19332.61504140133,6310.706142643705],
+ [19233.31504140133,6310.706142643705],
+ [19233.31504140133,6476.306142643704],
+ [19332.61504140133,6476.306142643704],
+ [19431.915041401327,6641.906142643704],
+ [19332.61504140133,6807.506142643703],
+ [19332.61504140133,6641.906142643704],
+ [19431.915041401327,6476.306142643704],
+ [19431.915041401327,6310.706142643705],
+ [19531.215041401327,6145.106142643705],
+ [19431.915041401327,5979.506142643706],
+ [19431.915041401327,6145.106142643705],
+ [19531.215041401327,5979.506142643706],
+ [19630.515041401326,5813.9061426437065],
+ [19630.515041401326,5979.506142643706],
+ [19729.815041401325,5813.9061426437065],
+ [19829.115041401325,5979.506142643706],
+ [19729.815041401325,5979.506142643706],
+ [19729.815041401325,6145.106142643705],
+ [19729.815041401325,6310.706142643705],
+ [19630.515041401326,6476.306142643704],
+ [19729.815041401325,6476.306142643704],
+ [19630.515041401326,6310.706142643705],
+ [19531.215041401327,6310.706142643705],
+ [19531.215041401327,6476.306142643704],
+ [19630.515041401326,6641.906142643704],
+ [19729.815041401325,6807.506142643703],
+ [19829.115041401325,6973.106142643703],
+ [19928.415041401324,6973.106142643703],
+ [19928.415041401324,7138.706142643702],
+ [20027.715041401323,7138.706142643702],
+ [20027.715041401323,7304.306142643702],
+ [19928.415041401324,7304.306142643702],
+ [19829.115041401325,7304.306142643702],
+ [19829.115041401325,7469.906142643701],
+ [19928.415041401324,7469.906142643701],
+ [19928.415041401324,7635.5061426437005],
+ [19928.415041401324,7801.1061426437],
+ [20027.715041401323,7635.5061426437005],
+ [20027.715041401323,7801.1061426437],
+ [20127.015041401322,7801.1061426437],
+ [20226.31504140132,7801.1061426437],
+ [20325.61504140132,7801.1061426437],
+ [20226.31504140132,7635.5061426437005],
+ [20226.31504140132,7469.906142643701],
+ [20226.31504140132,7304.306142643702],
+ [20127.015041401322,7304.306142643702],
+ [20027.715041401323,7469.906142643701],
+ [20127.015041401322,7469.906142643701],
+ [20127.015041401322,7635.5061426437005],
+ [2748.790306732237,2362.9553147492866],
+ [2848.0903067322365,2528.5553147492865],
+ [2748.790306732237,2694.1553147492864],
+ [2649.490306732237,2859.7553147492863],
+ [2748.790306732237,3025.355314749286],
+ [2848.0903067322365,2859.7553147492863],
+ [2848.0903067322365,2694.1553147492864],
+ [2947.3903067322362,2694.1553147492864],
+ [3046.690306732236,2859.7553147492863],
+ [3145.9903067322357,2694.1553147492864],
+ [3145.9903067322357,2528.5553147492865],
+ [3046.690306732236,2694.1553147492864],
+ [3145.9903067322357,2859.7553147492863],
+ [3046.690306732236,3025.355314749286],
+ [3145.9903067322357,3025.355314749286],
+ [3245.2903067322354,3190.955314749286],
+ [3245.2903067322354,3356.555314749286],
+ [3344.590306732235,3522.155314749286],
+ [3443.890306732235,3356.555314749286],
+ [3543.1903067322346,3356.555314749286],
+ [3642.4903067322343,3190.955314749286],
+ [3741.790306732234,3025.355314749286],
+ [3741.790306732234,2859.7553147492863],
+ [3841.090306732234,3025.355314749286],
+ [3841.090306732234,3190.955314749286],
+ [3741.790306732234,3190.955314749286],
+ [3642.4903067322343,3025.355314749286],
+ [3543.1903067322346,3025.355314749286],
+ [3543.1903067322346,2859.7553147492863],
+ [3443.890306732235,3025.355314749286],
+ [3443.890306732235,3190.955314749286],
+ [3543.1903067322346,3190.955314749286],
+ [3642.4903067322343,3356.555314749286],
+ [3543.1903067322346,3522.155314749286],
+ [3443.890306732235,3687.755314749286],
+ [3443.890306732235,3853.3553147492858],
+ [3344.590306732235,3687.755314749286],
+ [3245.2903067322354,3853.3553147492858],
+ [3245.2903067322354,3687.755314749286],
+ [3145.9903067322357,3687.755314749286],
+ [3046.690306732236,3853.3553147492858],
+ [3145.9903067322357,4018.9553147492857],
+ [3145.9903067322357,3853.3553147492858],
+ [3046.690306732236,3687.755314749286],
+ [3145.9903067322357,3522.155314749286],
+ [3145.9903067322357,3356.555314749286],
+ [3145.9903067322357,3190.955314749286],
+ [3046.690306732236,3190.955314749286],
+ [3046.690306732236,3356.555314749286],
+ [2947.3903067322362,3356.555314749286],
+ [2848.0903067322365,3190.955314749286],
+ [2947.3903067322362,3025.355314749286],
+ [2848.0903067322365,3025.355314749286],
+ [2748.790306732237,2859.7553147492863],
+ [2649.490306732237,2694.1553147492864],
+ [2748.790306732237,2528.5553147492865],
+ [2848.0903067322365,2362.9553147492866],
+ [2748.790306732237,2197.3553147492867],
+ [2649.490306732237,2362.9553147492866],
+ [2649.490306732237,2197.3553147492867],
+ [2550.1903067322373,2362.9553147492866],
+ [2450.8903067322376,2362.9553147492866],
+ [2351.590306732238,2528.5553147492865],
+ [2252.290306732238,2528.5553147492865],
+ [2351.590306732238,2362.9553147492866],
+ [2252.290306732238,2197.3553147492867],
+ [2351.590306732238,2197.3553147492867],
+ [2351.590306732238,2031.7553147492865],
+ [2351.590306732238,1866.1553147492864],
+ [2252.290306732238,1866.1553147492864],
+ [2351.590306732238,1700.5553147492863],
+ [2450.8903067322376,1534.9553147492861],
+ [2351.590306732238,1369.355314749286],
+ [2252.290306732238,1203.7553147492858],
+ [2252.290306732238,1369.355314749286],
+ [2252.290306732238,1534.9553147492861],
+ [2152.9903067322384,1369.355314749286],
+ [2053.6903067322387,1369.355314749286],
+ [1954.3903067322387,1203.7553147492858],
+ [1855.0903067322388,1203.7553147492858],
+ [1755.7903067322388,1038.1553147492857],
+ [1656.4903067322389,1038.1553147492857],
+ [1557.190306732239,872.5553147492857],
+ [1457.890306732239,1038.1553147492857],
+ [1457.890306732239,872.5553147492857],
+ [1457.890306732239,706.9553147492858],
+ [1557.190306732239,706.9553147492858],
+ [1656.4903067322389,872.5553147492857],
+ [1656.4903067322389,706.9553147492858],
+ [1755.7903067322388,706.9553147492858],
+ [1656.4903067322389,541.3553147492859],
+ [1557.190306732239,375.7553147492859],
+ [1656.4903067322389,210.1553147492859],
+ [1755.7903067322388,44.55531474928592],
+ [1656.4903067322389,44.55531474928592],
+ [1557.190306732239,210.1553147492859],
+ [1457.890306732239,210.1553147492859],
+ [1457.890306732239,44.55531474928592],
+ [1358.590306732239,210.1553147492859],
+ [1358.590306732239,375.75531474928584],
+ [1259.290306732239,210.15531474928585],
+ [1259.290306732239,375.75531474928584],
+ [1259.290306732239,541.3553147492859],
+ [1358.590306732239,706.9553147492858],
+ [1358.590306732239,872.5553147492857],
+ [1259.290306732239,706.9553147492858],
+ [1259.290306732239,872.5553147492857],
+ [1259.290306732239,1038.1553147492857],
+ [1358.590306732239,1203.7553147492858],
+ [1358.590306732239,1038.1553147492857],
+ [1457.890306732239,1203.7553147492858],
+ [1557.190306732239,1369.355314749286],
+ [1656.4903067322389,1203.7553147492858],
+ [1557.190306732239,1203.7553147492858],
+ [1557.190306732239,1038.1553147492857],
+ [17254.572515546668,1460.5807801244923],
+ [17353.872515546667,1626.1807801244925],
+ [17453.172515546667,1791.7807801244926],
+ [17552.472515546666,1791.7807801244926],
+ [17453.172515546667,1626.1807801244925],
+ [17353.872515546667,1791.7807801244926],
+ [17453.172515546667,1957.3807801244927],
+ [17353.872515546667,2122.980780124493],
+ [17453.172515546667,2288.580780124493],
+ [17353.872515546667,2454.1807801244927],
+ [17453.172515546667,2619.7807801244926],
+ [17552.472515546666,2619.7807801244926],
+ [17453.172515546667,2785.3807801244925],
+ [17353.872515546667,2619.7807801244926],
+ [17254.572515546668,2454.1807801244927],
+ [17254.572515546668,2288.580780124493],
+ [17353.872515546667,2288.580780124493],
+ [17453.172515546667,2122.980780124493],
+ [17552.472515546666,2288.580780124493],
+ [17552.472515546666,2454.1807801244927],
+ [17453.172515546667,2454.1807801244927],
+ [4447.67624466283,4761.1416826913],
+ [4546.97624466283,4595.541682691301],
+ [4546.97624466283,4429.941682691301],
+ [4447.67624466283,4429.941682691301],
+ [4447.67624466283,4595.541682691301],
+ [4348.37624466283,4595.541682691301],
+ [4249.07624466283,4595.541682691301],
+ [4348.37624466283,4761.1416826913],
+ [4249.07624466283,4761.1416826913],
+ [4348.37624466283,4926.7416826912995],
+ [4348.37624466283,5092.341682691299],
+ [4447.67624466283,5257.941682691298],
+ [4546.97624466283,5257.941682691298],
+ [4646.27624466283,5092.341682691299],
+ [4546.97624466283,5092.341682691299],
+ [4646.27624466283,4926.7416826912995],
+ [4646.27624466283,4761.1416826913],
+ [4546.97624466283,4761.1416826913],
+ [4646.27624466283,4595.541682691301],
+ [4745.5762446628305,4595.541682691301],
+ [4646.27624466283,4429.941682691301],
+ [4745.5762446628305,4429.941682691301],
+ [4844.876244662831,4595.541682691301],
+ [4745.5762446628305,4761.1416826913],
+ [4745.5762446628305,4926.7416826912995],
+ [4844.876244662831,4761.1416826913],
+ [4944.176244662831,4761.1416826913],
+ [5043.476244662831,4926.7416826912995],
+ [5043.476244662831,4761.1416826913],
+ [5142.776244662831,4926.7416826912995],
+ [5142.776244662831,4761.1416826913],
+ [5242.076244662831,4595.541682691301],
+ [5142.776244662831,4595.541682691301],
+ [5242.076244662831,4429.941682691301],
+ [5242.076244662831,4264.341682691302],
+ [5142.776244662831,4429.941682691301],
+ [5043.476244662831,4595.541682691301],
+ [5043.476244662831,4429.941682691301],
+ [5043.476244662831,4264.341682691302],
+ [5142.776244662831,4098.741682691302],
+ [5043.476244662831,4098.741682691302],
+ [4944.176244662831,3933.1416826913023],
+ [4944.176244662831,4098.741682691302],
+ [4944.176244662831,4264.341682691302],
+ [4844.876244662831,4098.741682691302],
+ [4745.5762446628305,4264.341682691302],
+ [4646.27624466283,4098.741682691302],
+ [4546.97624466283,3933.1416826913023],
+ [4447.67624466283,4098.741682691302],
+ [4546.97624466283,4264.341682691302],
+ [4447.67624466283,4264.341682691302],
+ [4546.97624466283,4098.741682691302],
+ [4646.27624466283,3933.1416826913023],
+ [4546.97624466283,3767.5416826913024],
+ [4447.67624466283,3601.9416826913025],
+ [4447.67624466283,3767.5416826913024],
+ [4348.37624466283,3767.5416826913024],
+ [4348.37624466283,3933.1416826913023],
+ [4249.07624466283,3767.5416826913024],
+ [4249.07624466283,3933.1416826913023],
+ [4149.776244662829,3933.1416826913023],
+ [4050.4762446628297,4098.741682691302],
+ [4050.4762446628297,3933.1416826913023],
+ [3951.17624466283,3933.1416826913023],
+ [3951.17624466283,4098.741682691302],
+ [3851.8762446628302,4264.341682691302],
+ [3851.8762446628302,4098.741682691302],
+ [3752.5762446628305,4098.741682691302],
+ [3653.276244662831,4264.341682691302],
+ [3553.976244662831,4429.941682691301],
+ [3553.976244662831,4595.541682691301],
+ [3454.6762446628313,4429.941682691301],
+ [3553.976244662831,4264.341682691302],
+ [3653.276244662831,4429.941682691301],
+ [3752.5762446628305,4264.341682691302],
+ [3752.5762446628305,4429.941682691301],
+ [3851.8762446628302,4595.541682691301],
+ [3851.8762446628302,4429.941682691301],
+ [3951.17624466283,4429.941682691301],
+ [4050.4762446628297,4264.341682691302],
+ [4149.776244662829,4098.741682691302],
+ [4249.07624466283,4264.341682691302],
+ [4348.37624466283,4098.741682691302],
+ [4447.67624466283,3933.1416826913023],
+ [9574.088902135607,7352.26293905581],
+ [9474.788902135606,7352.26293905581],
+ [9375.488902135605,7186.662939055811],
+ [9474.788902135606,7021.0629390558115],
+ [9574.088902135607,7021.0629390558115],
+ [9474.788902135606,7186.662939055811],
+ [9574.088902135607,7186.662939055811],
+ [9673.388902135608,7021.0629390558115],
+ [9673.388902135608,6855.462939055812],
+ [9772.68890213561,6689.862939055813],
+ [9673.388902135608,6689.862939055813],
+ [9772.68890213561,6524.262939055813],
+ [9871.98890213561,6358.662939055814],
+ [9971.288902135611,6524.262939055813],
+ [10070.588902135612,6358.662939055814],
+ [10070.588902135612,6193.062939055814],
+ [9971.288902135611,6027.462939055815],
+ [9971.288902135611,5861.862939055815],
+ [9871.98890213561,5861.862939055815],
+ [9871.98890213561,5696.262939055816],
+ [9971.288902135611,5530.662939055816],
+ [10070.588902135612,5530.662939055816],
+ [10070.588902135612,5696.262939055816],
+ [10169.888902135614,5861.862939055815],
+ [10169.888902135614,5696.262939055816],
+ [10070.588902135612,5861.862939055815],
+ [10169.888902135614,6027.462939055815],
+ [10169.888902135614,6193.062939055814],
+ [10269.188902135615,6027.462939055815],
+ [10269.188902135615,5861.862939055815],
+ [10368.488902135616,6027.462939055815],
+ [10269.188902135615,6193.062939055814],
+ [10269.188902135615,6358.662939055814],
+ [10169.888902135614,6358.662939055814],
+ [10070.588902135612,6524.262939055813],
+ [10070.588902135612,6689.862939055813],
+ [9971.288902135611,6855.462939055812],
+ [9971.288902135611,7021.0629390558115],
+ [10070.588902135612,7186.662939055811],
+ [10169.888902135614,7186.662939055811],
+ [10269.188902135615,7186.662939055811],
+ [10169.888902135614,7352.26293905581],
+ [10070.588902135612,7352.26293905581],
+ [10169.888902135614,7517.86293905581],
+ [10169.888902135614,7683.462939055809],
+ [10269.188902135615,7517.86293905581],
+ [10368.488902135616,7683.462939055809],
+ [10467.788902135617,7683.462939055809],
+ [10368.488902135616,7517.86293905581],
+ [10269.188902135615,7352.26293905581],
+ [10368.488902135616,7352.26293905581],
+ [10368.488902135616,7186.662939055811],
+ [10368.488902135616,7021.0629390558115],
+ [10368.488902135616,6855.462939055812],
+ [10269.188902135615,6855.462939055812],
+ [10169.888902135614,6855.462939055812],
+ [10169.888902135614,7021.0629390558115],
+ [10070.588902135612,7021.0629390558115],
+ [10070.588902135612,6855.462939055812],
+ [10169.888902135614,6689.862939055813],
+ [10269.188902135615,6689.862939055813],
+ [10169.888902135614,6524.262939055813],
+ [10269.188902135615,6524.262939055813],
+ [10368.488902135616,6524.262939055813],
+ [10368.488902135616,6358.662939055814],
+ [10467.788902135617,6358.662939055814],
+ [10467.788902135617,6193.062939055814],
+ [10567.088902135618,6358.662939055814],
+ [10567.088902135618,6193.062939055814],
+ [10666.388902135619,6193.062939055814],
+ [10666.388902135619,6358.662939055814],
+ [10567.088902135618,6524.262939055813],
+ [10467.788902135617,6524.262939055813],
+ [10567.088902135618,6689.862939055813],
+ [10467.788902135617,6855.462939055812],
+ [10567.088902135618,7021.0629390558115],
+ [10467.788902135617,7021.0629390558115],
+ [10567.088902135618,6855.462939055812],
+ [10467.788902135617,6689.862939055813],
+ [10368.488902135616,6689.862939055813],
+ [1073.6944354374714,1154.3681204032646],
+ [974.3944354374713,1319.9681204032647],
+ [875.0944354374712,1319.9681204032647],
+ [775.7944354374712,1154.3681204032646],
+ [775.7944354374712,988.7681204032646],
+ [875.0944354374712,823.1681204032647],
+ [875.0944354374712,657.5681204032647],
+ [775.7944354374712,823.1681204032647],
+ [676.4944354374711,657.5681204032647],
+ [676.4944354374711,491.9681204032648],
+ [775.7944354374712,657.5681204032647],
+ [676.4944354374711,823.1681204032647],
+ [676.4944354374711,988.7681204032646],
+ [577.194435437471,823.1681204032647],
+ [577.194435437471,988.7681204032646],
+ [577.194435437471,1154.3681204032646],
+ [676.4944354374711,1319.9681204032647],
+ [577.194435437471,1319.9681204032647],
+ [477.89443543747103,1319.9681204032647],
+ [577.194435437471,1485.5681204032649],
+ [477.89443543747103,1651.168120403265],
+ [577.194435437471,1816.7681204032651],
+ [477.89443543747103,1816.7681204032651],
+ [378.5944354374711,1982.3681204032653],
+ [378.5944354374711,2147.9681204032654],
+ [279.2944354374711,2313.5681204032653],
+ [179.99443543747114,2147.9681204032654],
+ [80.69443543747114,2313.5681204032653],
+ [80.69443543747114,2479.168120403265],
+ [179.9944354374711,2644.768120403265],
+ [179.9944354374711,2479.168120403265],
+ [179.9944354374711,2313.5681204032653],
+ [80.69443543747111,2147.9681204032654],
+ [80.69443543747111,1982.3681204032653],
+ [179.9944354374711,1982.3681204032653],
+ [179.9944354374711,1816.7681204032651],
+ [80.69443543747111,1816.7681204032651],
+ [179.9944354374711,1651.168120403265],
+ [80.69443543747111,1485.5681204032649],
+ [80.69443543747111,1319.9681204032647],
+ [179.9944354374711,1154.3681204032646],
+ [80.69443543747111,1154.3681204032646],
+ [179.9944354374711,988.7681204032646],
+ [279.2944354374711,823.1681204032647],
+ [378.5944354374711,657.5681204032647],
+ [378.5944354374711,823.1681204032647],
+ [477.89443543747103,823.1681204032647],
+ [477.89443543747103,657.5681204032647],
+ [378.5944354374711,491.9681204032648],
+ [477.89443543747103,326.3681204032648],
+ [477.89443543747103,160.76812040326482],
+ [378.5944354374711,160.76812040326482],
+ [279.2944354374711,326.3681204032648],
+ [179.99443543747114,491.9681204032648],
+ [179.99443543747114,326.3681204032648],
+ [279.2944354374711,491.9681204032648],
+ [279.2944354374711,657.5681204032647],
+ [179.99443543747114,823.1681204032647],
+ [279.2944354374711,988.7681204032646],
+ [279.2944354374711,1154.3681204032646],
+ [378.5944354374711,1319.9681204032647],
+ [477.89443543747103,1485.5681204032649],
+ [577.194435437471,1651.168120403265],
+ [676.4944354374711,1651.168120403265],
+ [775.7944354374712,1816.7681204032651],
+ [676.4944354374711,1816.7681204032651],
+ [775.7944354374712,1651.168120403265],
+ [875.0944354374712,1651.168120403265],
+ [974.3944354374713,1651.168120403265],
+ [875.0944354374712,1485.5681204032649],
+ [775.7944354374712,1485.5681204032649],
+ [676.4944354374711,1485.5681204032649],
+ [775.7944354374712,1319.9681204032647],
+ [676.4944354374711,1154.3681204032646],
+ [3138.413562431697,2355.845602060523],
+ [3039.113562431697,2521.445602060523],
+ [3039.113562431697,2355.845602060523],
+ [3039.113562431697,2190.245602060523],
+ [3138.413562431697,2024.645602060523],
+ [3237.7135624316966,1859.045602060523],
+ [3237.7135624316966,2024.645602060523],
+ [3337.0135624316963,1859.045602060523],
+ [3337.0135624316963,1693.4456020605228],
+ [3436.313562431696,1527.8456020605227],
+ [3535.6135624316958,1693.4456020605228],
+ [3535.6135624316958,1859.045602060523],
+ [3634.9135624316955,2024.645602060523],
+ [3734.213562431695,2190.245602060523],
+ [3634.9135624316955,2190.245602060523],
+ [3535.6135624316958,2190.245602060523],
+ [3535.6135624316958,2355.845602060523],
+ [3535.6135624316958,2521.445602060523],
+ [3436.313562431696,2687.045602060523],
+ [3436.313562431696,2852.645602060523],
+ [3535.6135624316958,2687.045602060523],
+ [3634.9135624316955,2521.445602060523],
+ [3634.9135624316955,2355.845602060523],
+ [3734.213562431695,2355.845602060523],
+ [3833.513562431695,2190.245602060523],
+ [3932.8135624316947,2024.645602060523],
+ [3833.513562431695,1859.045602060523],
+ [3833.513562431695,1693.4456020605228],
+ [3734.213562431695,1859.045602060523],
+ [3734.213562431695,1693.4456020605228],
+ [3734.213562431695,1527.8456020605227],
+ [3634.9135624316955,1527.8456020605227],
+ [3634.9135624316955,1693.4456020605228],
+ [3535.6135624316958,1527.8456020605227],
+ [3634.9135624316955,1362.2456020605225],
+ [3535.6135624316958,1362.2456020605225],
+ [3436.313562431696,1196.6456020605224],
+ [3535.6135624316958,1196.6456020605224],
+ [3535.6135624316958,1031.0456020605222],
+ [3436.313562431696,1031.0456020605222],
+ [3535.6135624316958,865.4456020605222],
+ [3436.313562431696,865.4456020605222],
+ [3535.6135624316958,699.8456020605223],
+ [3634.9135624316955,699.8456020605223],
+ [3535.6135624316958,534.2456020605224],
+ [3436.313562431696,368.64560206052244],
+ [3436.313562431696,203.04560206052244],
+ [3337.0135624316963,37.445602060522454],
+ [3436.313562431696,37.445602060522454],
+ [3337.0135624316963,203.04560206052244],
+ [3237.7135624316966,37.445602060522454],
+ [3138.413562431697,37.445602060522454],
+ [3237.7135624316966,203.04560206052244],
+ [3337.0135624316963,368.6456020605224],
+ [3436.313562431696,534.2456020605224],
+ [3337.0135624316963,699.8456020605223],
+ [3237.7135624316966,534.2456020605224],
+ [3337.0135624316963,534.2456020605224],
+ [3436.313562431696,699.8456020605223],
+ [3337.0135624316963,865.4456020605222],
+ [3237.7135624316966,865.4456020605222],
+ [3337.0135624316963,1031.0456020605222],
+ [3237.7135624316966,1196.6456020605224],
+ [3138.413562431697,1362.2456020605225],
+ [3039.113562431697,1527.8456020605227],
+ [3138.413562431697,1527.8456020605227],
+ [3039.113562431697,1693.4456020605228],
+ [2939.8135624316974,1527.8456020605227],
+ [2840.5135624316977,1362.2456020605225],
+ [2840.5135624316977,1527.8456020605227],
+ [2840.5135624316977,1693.4456020605228],
+ [2939.8135624316974,1859.045602060523],
+ [2840.5135624316977,2024.645602060523],
+ [2840.5135624316977,1859.045602060523],
+ [2939.8135624316974,1693.4456020605228],
+ [3039.113562431697,1859.045602060523],
+ [3039.113562431697,2024.645602060523],
+ [2939.8135624316974,2190.245602060523],
+ [2939.8135624316974,2024.645602060523],
+ [16388.412117675925,1839.818884803299],
+ [16289.112117675924,1839.818884803299],
+ [16388.412117675925,1674.2188848032988],
+ [16487.712117675925,1508.6188848032987],
+ [16487.712117675925,1674.2188848032988],
+ [16388.412117675925,1508.6188848032987],
+ [16289.112117675924,1343.0188848032985],
+ [16289.112117675924,1508.6188848032987],
+ [16189.812117675923,1674.2188848032988],
+ [16090.512117675922,1839.818884803299],
+ [16090.512117675922,2005.418884803299],
+ [15991.212117675921,2171.018884803299],
+ [16090.512117675922,2336.618884803299],
+ [16090.512117675922,2502.218884803299],
+ [16090.512117675922,2667.8188848032987],
+ [15991.212117675921,2833.4188848032986],
+ [15991.212117675921,2999.0188848032985],
+ [15891.91211767592,3164.6188848032984],
+ [15891.91211767592,3330.2188848032984],
+ [15991.212117675921,3330.2188848032984],
+ [16090.512117675922,3330.2188848032984],
+ [16189.812117675923,3495.8188848032983],
+ [16289.112117675924,3495.8188848032983],
+ [16189.812117675923,3330.2188848032984],
+ [16189.812117675923,3164.6188848032984],
+ [16289.112117675924,3164.6188848032984],
+ [16388.412117675925,3164.6188848032984],
+ [16388.412117675925,3330.2188848032984],
+ [16487.712117675925,3330.2188848032984],
+ [16587.012117675924,3495.8188848032983],
+ [16587.012117675924,3661.418884803298],
+ [16686.312117675923,3661.418884803298],
+ [16785.612117675922,3661.418884803298],
+ [16884.91211767592,3661.418884803298],
+ [16984.21211767592,3661.418884803298],
+ [16884.91211767592,3827.018884803298],
+ [16884.91211767592,3992.618884803298],
+ [16984.21211767592,3827.018884803298],
+ [17083.51211767592,3661.418884803298],
+ [17182.81211767592,3495.8188848032983],
+ [17182.81211767592,3330.2188848032984],
+ [17282.11211767592,3164.6188848032984],
+ [17282.11211767592,3330.2188848032984],
+ [17182.81211767592,3164.6188848032984],
+ [17083.51211767592,3164.6188848032984],
+ [16984.21211767592,3330.2188848032984],
+ [16984.21211767592,3495.8188848032983],
+ [17083.51211767592,3330.2188848032984],
+ [16984.21211767592,3164.6188848032984],
+ [16984.21211767592,2999.0188848032985],
+ [17083.51211767592,2833.4188848032986],
+ [17083.51211767592,2667.8188848032987],
+ [17182.81211767592,2667.8188848032987],
+ [17182.81211767592,2833.4188848032986],
+ [17083.51211767592,2999.0188848032985],
+ [16984.21211767592,2833.4188848032986],
+ [16884.91211767592,2833.4188848032986],
+ [16884.91211767592,2999.0188848032985],
+ [16785.612117675922,2999.0188848032985],
+ [16884.91211767592,3164.6188848032984],
+ [16785.612117675922,3164.6188848032984],
+ [16686.312117675923,3164.6188848032984],
+ [16587.012117675924,3164.6188848032984],
+ [16587.012117675924,2999.0188848032985],
+ [16487.712117675925,3164.6188848032984],
+ [16587.012117675924,3330.2188848032984],
+ [16686.312117675923,3495.8188848032983],
+ [16686.312117675923,3330.2188848032984],
+ [16785.612117675922,3330.2188848032984],
+ [16884.91211767592,3495.8188848032983],
+ [16785.612117675922,3495.8188848032983],
+ [16884.91211767592,3330.2188848032984],
+ [1272.175991128079,3842.7700224365044],
+ [1371.475991128079,3842.7700224365044],
+ [1272.175991128079,3677.1700224365045],
+ [1172.875991128079,3511.5700224365046],
+ [1272.175991128079,3511.5700224365046],
+ [1172.875991128079,3345.9700224365047],
+ [1073.575991128079,3180.3700224365048],
+ [1073.575991128079,3014.770022436505],
+ [974.275991128079,3014.770022436505],
+ [874.9759911280789,3014.770022436505],
+ [775.6759911280789,2849.170022436505],
+ [775.6759911280789,3014.770022436505],
+ [775.6759911280789,3180.3700224365048],
+ [676.3759911280788,3345.9700224365047],
+ [676.3759911280788,3511.5700224365046],
+ [775.6759911280789,3677.1700224365045],
+ [676.3759911280788,3842.7700224365044],
+ [577.0759911280787,3842.7700224365044],
+ [577.0759911280787,3677.1700224365045],
+ [676.3759911280788,3677.1700224365045],
+ [775.6759911280789,3511.5700224365046],
+ [775.6759911280789,3345.9700224365047],
+ [874.9759911280789,3345.9700224365047],
+ [874.9759911280789,3180.3700224365048],
+ [974.275991128079,3180.3700224365048],
+ [974.275991128079,3345.9700224365047],
+ [1073.575991128079,3511.5700224365046],
+ [1073.575991128079,3677.1700224365045],
+ [1172.875991128079,3677.1700224365045],
+ [1172.875991128079,3842.7700224365044],
+ [1073.575991128079,3842.7700224365044],
+ [1172.875991128079,4008.3700224365043],
+ [1073.575991128079,4008.3700224365043],
+ [974.275991128079,3842.7700224365044],
+ [974.275991128079,4008.3700224365043],
+ [874.9759911280789,4008.3700224365043],
+ [775.6759911280789,4008.3700224365043],
+ [874.9759911280789,3842.7700224365044],
+ [974.275991128079,3677.1700224365045],
+ [974.275991128079,3511.5700224365046],
+ [1073.575991128079,3345.9700224365047],
+ [1172.875991128079,3180.3700224365048],
+ [1272.175991128079,3180.3700224365048],
+ [1272.175991128079,3345.9700224365047],
+ [1371.475991128079,3180.3700224365048],
+ [1470.7759911280789,3345.9700224365047],
+ [1371.475991128079,3345.9700224365047],
+ [1371.475991128079,3511.5700224365046],
+ [1470.7759911280789,3511.5700224365046],
+ [1570.0759911280788,3677.1700224365045],
+ [1470.7759911280789,3677.1700224365045],
+ [1570.0759911280788,3511.5700224365046],
+ [1669.3759911280788,3511.5700224365046],
+ [1669.3759911280788,3677.1700224365045],
+ [1768.6759911280787,3842.7700224365044],
+ [1669.3759911280788,3842.7700224365044],
+ [1768.6759911280787,4008.3700224365043],
+ [1867.9759911280787,3842.7700224365044],
+ [1967.2759911280787,3677.1700224365045],
+ [2066.5759911280784,3842.7700224365044],
+ [2165.875991128078,3677.1700224365045],
+ [2066.5759911280784,3511.5700224365046],
+ [2165.875991128078,3511.5700224365046],
+ [2066.5759911280784,3677.1700224365045],
+ [2165.875991128078,3842.7700224365044],
+ [2265.175991128078,4008.3700224365043],
+ [2364.4759911280776,4008.3700224365043],
+ [2265.175991128078,3842.7700224365044],
+ [2364.4759911280776,3677.1700224365045],
+ [2463.7759911280773,3842.7700224365044],
+ [2463.7759911280773,4008.3700224365043],
+ [2364.4759911280776,3842.7700224365044],
+ [6853.940039224797,6050.837897021371],
+ [6953.240039224797,6050.837897021371],
+ [7052.5400392247975,5885.237897021371],
+ [7052.5400392247975,5719.637897021372],
+ [7151.840039224798,5885.237897021371],
+ [7052.5400392247975,6050.837897021371],
+ [7052.5400392247975,6216.43789702137],
+ [7052.5400392247975,6382.03789702137],
+ [6953.240039224797,6382.03789702137],
+ [6953.240039224797,6216.43789702137],
+ [6853.940039224797,6216.43789702137],
+ [6853.940039224797,6382.03789702137],
+ [6754.640039224797,6216.43789702137],
+ [6754.640039224797,6382.03789702137],
+ [6754.640039224797,6547.637897021369],
+ [6754.640039224797,6713.237897021369],
+ [6655.340039224797,6713.237897021369],
+ [6754.640039224797,6878.837897021368],
+ [6853.940039224797,6713.237897021369],
+ [6853.940039224797,6878.837897021368],
+ [6953.240039224797,6713.237897021369],
+ [7052.5400392247975,6547.637897021369],
+ [7151.840039224798,6713.237897021369],
+ [7151.840039224798,6547.637897021369],
+ [7151.840039224798,6382.03789702137],
+ [7251.140039224798,6547.637897021369],
+ [7251.140039224798,6713.237897021369],
+ [7350.440039224798,6878.837897021368],
+ [7449.740039224798,6878.837897021368],
+ [7449.740039224798,6713.237897021369],
+ [7549.040039224798,6547.637897021369],
+ [7449.740039224798,6382.03789702137],
+ [7449.740039224798,6216.43789702137],
+ [7549.040039224798,6050.837897021371],
+ [7648.340039224799,6216.43789702137],
+ [7549.040039224798,6382.03789702137],
+ [7648.340039224799,6382.03789702137],
+ [7747.640039224799,6216.43789702137],
+ [7846.940039224799,6382.03789702137],
+ [7946.240039224799,6382.03789702137],
+ [7946.240039224799,6547.637897021369],
+ [7846.940039224799,6713.237897021369],
+ [7946.240039224799,6713.237897021369],
+ [8045.540039224799,6547.637897021369],
+ [8045.540039224799,6713.237897021369],
+ [7946.240039224799,6878.837897021368],
+ [7946.240039224799,7044.4378970213675],
+ [8045.540039224799,7210.037897021367],
+ [8144.8400392247995,7375.637897021366],
+ [8144.8400392247995,7541.237897021366],
+ [8045.540039224799,7375.637897021366],
+ [8144.8400392247995,7210.037897021367],
+ [8045.540039224799,7044.4378970213675],
+ [7946.240039224799,7210.037897021367],
+ [7846.940039224799,7210.037897021367],
+ [7946.240039224799,7375.637897021366],
+ [8045.540039224799,7541.237897021366],
+ [8144.8400392247995,7706.837897021365],
+ [8244.1400392248,7541.237897021366],
+ [8343.4400392248,7541.237897021366],
+ [8343.4400392248,7706.837897021365],
+ [8244.1400392248,7706.837897021365],
+ [4735.523842661975,3503.497768214323],
+ [4636.223842661975,3337.897768214323],
+ [4536.923842661975,3337.897768214323],
+ [4437.623842661975,3172.2977682143232],
+ [4338.323842661975,3172.2977682143232],
+ [4239.023842661974,3172.2977682143232],
+ [4338.323842661975,3006.6977682143233],
+ [4437.623842661975,2841.0977682143234],
+ [4338.323842661975,2675.4977682143235],
+ [4338.323842661975,2509.8977682143236],
+ [4239.023842661974,2675.4977682143235],
+ [4139.723842661974,2509.8977682143236],
+ [4040.4238426619745,2344.2977682143237],
+ [4139.723842661974,2178.697768214324],
+ [4239.023842661974,2178.697768214324],
+ [4139.723842661974,2344.2977682143237],
+ [4040.4238426619745,2178.697768214324],
+ [4139.723842661974,2013.0977682143237],
+ [4139.723842661974,1847.4977682143235],
+ [4239.023842661974,2013.0977682143237],
+ [4239.023842661974,1847.4977682143235],
+ [4338.323842661975,1847.4977682143235],
+ [4437.623842661975,1847.4977682143235],
+ [4536.923842661975,1681.8977682143234],
+ [4437.623842661975,1516.2977682143232],
+ [4536.923842661975,1516.2977682143232],
+ [4536.923842661975,1350.697768214323],
+ [4437.623842661975,1350.697768214323],
+ [4536.923842661975,1185.097768214323],
+ [4636.223842661975,1019.497768214323],
+ [4536.923842661975,853.897768214323],
+ [4636.223842661975,853.897768214323],
+ [4735.523842661975,688.2977682143231],
+ [4636.223842661975,522.6977682143232],
+ [4636.223842661975,357.09776821432325],
+ [4735.523842661975,357.09776821432325],
+ [4735.523842661975,522.6977682143232],
+ [4636.223842661975,688.2977682143231],
+ [4735.523842661975,853.897768214323],
+ [4834.8238426619755,853.897768214323],
+ [4735.523842661975,1019.497768214323],
+ [4735.523842661975,1185.097768214323],
+ [4735.523842661975,1350.697768214323],
+ [4834.8238426619755,1516.2977682143232],
+ [4735.523842661975,1516.2977682143232],
+ [4834.8238426619755,1350.697768214323],
+ [4834.8238426619755,1185.097768214323],
+ [4934.123842661976,1350.697768214323],
+ [5033.423842661976,1185.097768214323],
+ [5033.423842661976,1019.497768214323],
+ [5033.423842661976,853.897768214323],
+ [4934.123842661976,853.897768214323],
+ [4934.123842661976,1019.497768214323],
+ [4834.8238426619755,1019.497768214323],
+ [4934.123842661976,1185.097768214323],
+ [5033.423842661976,1350.697768214323],
+ [5132.723842661976,1350.697768214323],
+ [5132.723842661976,1185.097768214323],
+ [5232.023842661976,1019.497768214323],
+ [5232.023842661976,1185.097768214323],
+ [5331.323842661976,1019.497768214323],
+ [5430.623842661977,1019.497768214323],
+ [5529.923842661977,1185.097768214323],
+ [5430.623842661977,1350.697768214323],
+ [5430.623842661977,1516.2977682143232],
+ [5529.923842661977,1350.697768214323],
+ [5629.223842661977,1350.697768214323],
+ [5728.523842661977,1350.697768214323],
+ [5728.523842661977,1516.2977682143232],
+ [5728.523842661977,1681.8977682143234],
+ [5629.223842661977,1516.2977682143232],
+ [5529.923842661977,1516.2977682143232],
+ [5629.223842661977,1681.8977682143234],
+ [5529.923842661977,1681.8977682143234],
+ [5430.623842661977,1847.4977682143235],
+ [5331.323842661976,1847.4977682143235],
+ [5331.323842661976,2013.0977682143237],
+ [5232.023842661976,2178.697768214324],
+ [5132.723842661976,2013.0977682143237],
+ [5132.723842661976,2178.697768214324],
+ [5232.023842661976,2013.0977682143237],
+ [5232.023842661976,1847.4977682143235],
+ [5232.023842661976,1681.8977682143234],
+ [5331.323842661976,1681.8977682143234],
+ [5331.323842661976,1516.2977682143232],
+ [5331.323842661976,1350.697768214323],
+ [5232.023842661976,1350.697768214323],
+ [5232.023842661976,1516.2977682143232],
+ [5132.723842661976,1516.2977682143232],
+ [5132.723842661976,1681.8977682143234],
+ [5033.423842661976,1847.4977682143235],
+ [5132.723842661976,1847.4977682143235],
+ [5033.423842661976,2013.0977682143237],
+ [4934.123842661976,2178.697768214324],
+ [5033.423842661976,2344.2977682143237],
+ [4934.123842661976,2344.2977682143237],
+ [4834.8238426619755,2178.697768214324],
+ [4834.8238426619755,2344.2977682143237],
+ [4735.523842661975,2344.2977682143237],
+ [4636.223842661975,2344.2977682143237],
+ [4536.923842661975,2178.697768214324],
+ [4437.623842661975,2013.0977682143237],
+ [4338.323842661975,2178.697768214324],
+ [4437.623842661975,2344.2977682143237],
+ [4536.923842661975,2509.8977682143236],
+ [4636.223842661975,2675.4977682143235],
+ [4636.223842661975,2509.8977682143236],
+ [4536.923842661975,2675.4977682143235],
+ [4636.223842661975,2841.0977682143234],
+ [4536.923842661975,2841.0977682143234],
+ [4636.223842661975,3006.6977682143233],
+ [4735.523842661975,3172.2977682143232],
+ [4834.8238426619755,3006.6977682143233],
+ [4735.523842661975,2841.0977682143234],
+ [4735.523842661975,3006.6977682143233],
+ [4636.223842661975,3172.2977682143232],
+ [4735.523842661975,3337.897768214323],
+ [4834.8238426619755,3503.497768214323],
+ [4735.523842661975,3669.097768214323],
+ [4834.8238426619755,3834.697768214323],
+ [4834.8238426619755,3669.097768214323],
+ [4934.123842661976,3503.497768214323],
+ [5033.423842661976,3503.497768214323],
+ [5033.423842661976,3337.897768214323],
+ [4934.123842661976,3337.897768214323],
+ [4834.8238426619755,3172.2977682143232],
+ [4834.8238426619755,3337.897768214323],
+ [4934.123842661976,3172.2977682143232],
+ [5033.423842661976,3006.6977682143233],
+ [5132.723842661976,2841.0977682143234],
+ [5132.723842661976,3006.6977682143233],
+ [5232.023842661976,3172.2977682143232],
+ [5232.023842661976,3337.897768214323],
+ [5132.723842661976,3337.897768214323],
+ [5232.023842661976,3503.497768214323],
+ [5331.323842661976,3337.897768214323],
+ [5331.323842661976,3503.497768214323],
+ [5430.623842661977,3669.097768214323],
+ [5331.323842661976,3669.097768214323],
+ [5430.623842661977,3503.497768214323],
+ [5430.623842661977,3337.897768214323],
+ [5529.923842661977,3172.2977682143232],
+ [5529.923842661977,3337.897768214323],
+ [5629.223842661977,3337.897768214323],
+ [5728.523842661977,3337.897768214323],
+ [5728.523842661977,3503.497768214323],
+ [5827.823842661977,3503.497768214323],
+ [5927.1238426619775,3669.097768214323],
+ [6026.423842661978,3669.097768214323],
+ [6125.723842661978,3503.497768214323],
+ [6125.723842661978,3669.097768214323],
+ [6225.023842661978,3503.497768214323],
+ [6225.023842661978,3337.897768214323],
+ [6324.323842661978,3337.897768214323],
+ [6423.623842661978,3503.497768214323],
+ [6324.323842661978,3669.097768214323],
+ [6225.023842661978,3669.097768214323],
+ [6324.323842661978,3834.697768214323],
+ [6423.623842661978,3834.697768214323],
+ [6324.323842661978,4000.297768214323],
+ [6225.023842661978,3834.697768214323],
+ [6125.723842661978,3834.697768214323],
+ [6125.723842661978,4000.297768214323],
+ [6225.023842661978,4000.297768214323],
+ [6225.023842661978,4165.897768214322],
+ [6225.023842661978,4331.497768214322],
+ [6125.723842661978,4165.897768214322],
+ [6026.423842661978,4000.2977682143223],
+ [5927.1238426619775,4165.897768214322],
+ [6026.423842661978,4331.497768214322],
+ [6026.423842661978,4497.097768214321],
+ [5927.1238426619775,4497.097768214321],
+ [5827.823842661977,4662.697768214321],
+ [5728.523842661977,4828.29776821432],
+ [5827.823842661977,4828.29776821432],
+ [5927.1238426619775,4828.29776821432],
+ [5927.1238426619775,4662.697768214321],
+ [5827.823842661977,4497.097768214321],
+ [5927.1238426619775,4331.497768214322],
+ [5827.823842661977,4165.897768214322],
+ [5728.523842661977,4331.497768214322],
+ [5728.523842661977,4165.897768214322],
+ [5629.223842661977,4000.2977682143223],
+ [5629.223842661977,3834.6977682143224],
+ [5529.923842661977,3669.0977682143225],
+ [5629.223842661977,3503.4977682143226],
+ [5728.523842661977,3669.0977682143225],
+ [5827.823842661977,3669.0977682143225],
+ [5927.1238426619775,3834.6977682143224],
+ [5927.1238426619775,4000.2977682143223],
+ [6026.423842661978,4165.897768214322],
+ [6125.723842661978,4331.497768214322],
+ [6225.023842661978,4497.097768214321],
+ [6225.023842661978,4662.697768214321],
+ [6324.323842661978,4662.697768214321],
+ [6225.023842661978,4828.29776821432],
+ [6324.323842661978,4828.29776821432],
+ [6423.623842661978,4828.29776821432],
+ [6324.323842661978,4993.8977682143195],
+ [6225.023842661978,5159.497768214319],
+ [6125.723842661978,5159.497768214319],
+ [6026.423842661978,5325.097768214318],
+ [5927.1238426619775,5490.697768214318],
+ [6026.423842661978,5656.297768214317],
+ [5927.1238426619775,5821.897768214317],
+ [5927.1238426619775,5987.497768214316],
+ [6026.423842661978,5987.497768214316],
+ [6026.423842661978,5821.897768214317],
+ [5927.1238426619775,5656.297768214317],
+ [5827.823842661977,5656.297768214317],
+ [5827.823842661977,5490.697768214318],
+ [5728.523842661977,5490.697768214318],
+ [5629.223842661977,5325.097768214318],
+ [5629.223842661977,5159.497768214319],
+ [5529.923842661977,4993.8977682143195],
+ [5529.923842661977,5159.497768214319],
+ [5629.223842661977,4993.8977682143195],
+ [5629.223842661977,4828.29776821432],
+ [5529.923842661977,4662.697768214321],
+ [5430.623842661977,4828.29776821432],
+ [5529.923842661977,4828.29776821432],
+ [5629.223842661977,4662.697768214321],
+ [5728.523842661977,4662.697768214321],
+ [5629.223842661977,4497.097768214321],
+ [5728.523842661977,4497.097768214321],
+ [5827.823842661977,4331.497768214322],
+ [10216.161365168813,2951.605409896135],
+ [10116.861365168812,2951.605409896135],
+ [10017.56136516881,3117.205409896135],
+ [9918.26136516881,3117.205409896135],
+ [9818.961365168809,3117.205409896135],
+ [9719.661365168808,3282.8054098961347],
+ [9620.361365168807,3282.8054098961347],
+ [9620.361365168807,3117.205409896135],
+ [9521.061365168805,2951.605409896135],
+ [9521.061365168805,2786.005409896135],
+ [9620.361365168807,2786.005409896135],
+ [9719.661365168808,2786.005409896135],
+ [9818.961365168809,2620.405409896135],
+ [9918.26136516881,2786.005409896135],
+ [9818.961365168809,2951.605409896135],
+ [9818.961365168809,2786.005409896135],
+ [9719.661365168808,2620.405409896135],
+ [9719.661365168808,2454.805409896135],
+ [9620.361365168807,2289.2054098961353],
+ [9521.061365168805,2123.6054098961354],
+ [9620.361365168807,1958.0054098961352],
+ [9719.661365168808,2123.6054098961354],
+ [9818.961365168809,2289.2054098961353],
+ [9818.961365168809,2123.6054098961354],
+ [9818.961365168809,1958.0054098961352],
+ [9719.661365168808,1958.0054098961352],
+ [9620.361365168807,1792.405409896135],
+ [9620.361365168807,1626.805409896135],
+ [9521.061365168805,1461.2054098961348],
+ [9421.761365168804,1295.6054098961347],
+ [9521.061365168805,1130.0054098961346],
+ [9521.061365168805,964.4054098961345],
+ [9421.761365168804,964.4054098961345],
+ [9521.061365168805,798.8054098961346],
+ [9620.361365168807,798.8054098961346],
+ [9620.361365168807,964.4054098961345],
+ [9620.361365168807,1130.0054098961346],
+ [9620.361365168807,1295.6054098961347],
+ [9620.361365168807,1461.2054098961348],
+ [9719.661365168808,1295.6054098961347],
+ [9818.961365168809,1130.0054098961346],
+ [9918.26136516881,964.4054098961345],
+ [9818.961365168809,964.4054098961345],
+ [9918.26136516881,798.8054098961346],
+ [10017.56136516881,633.2054098961347],
+ [9918.26136516881,467.60540989613474],
+ [9918.26136516881,302.0054098961348],
+ [10017.56136516881,302.0054098961348],
+ [10116.861365168812,136.40540989613478],
+ [10116.861365168812,302.0054098961348],
+ [10116.861365168812,467.60540989613474],
+ [10116.861365168812,633.2054098961347],
+ [10216.161365168813,633.2054098961347],
+ [10216.161365168813,798.8054098961346],
+ [10315.461365168814,633.2054098961347],
+ [10315.461365168814,798.8054098961346],
+ [10414.761365168815,798.8054098961346],
+ [10514.061365168816,633.2054098961347],
+ [10514.061365168816,798.8054098961346],
+ [10414.761365168815,964.4054098961345],
+ [10315.461365168814,964.4054098961345],
+ [10216.161365168813,964.4054098961345],
+ [10116.861365168812,798.8054098961346],
+ [10017.56136516881,798.8054098961346],
+ [10116.861365168812,964.4054098961345],
+ [10216.161365168813,1130.0054098961346],
+ [10116.861365168812,1130.0054098961346],
+ [10216.161365168813,1295.6054098961347],
+ [10216.161365168813,1461.2054098961348],
+ [10315.461365168814,1626.805409896135],
+ [10315.461365168814,1792.405409896135],
+ [10216.161365168813,1958.0054098961352],
+ [10216.161365168813,1792.405409896135],
+ [10116.861365168812,1792.405409896135],
+ [10017.56136516881,1958.0054098961352],
+ [9918.26136516881,2123.6054098961354],
+ [9918.26136516881,1958.0054098961352],
+ [10017.56136516881,2123.6054098961354],
+ [10116.861365168812,2123.6054098961354],
+ [10017.56136516881,2289.2054098961353],
+ [10017.56136516881,2454.805409896135],
+ [10116.861365168812,2289.2054098961353],
+ [10216.161365168813,2454.805409896135],
+ [10315.461365168814,2620.405409896135],
+ [10315.461365168814,2454.805409896135],
+ [10315.461365168814,2289.2054098961353],
+ [10414.761365168815,2454.805409896135],
+ [10514.061365168816,2620.405409896135],
+ [10613.361365168817,2786.005409896135],
+ [10514.061365168816,2786.005409896135],
+ [10613.361365168817,2620.405409896135],
+ [10514.061365168816,2454.805409896135],
+ [10514.061365168816,2289.2054098961353],
+ [10613.361365168817,2289.2054098961353],
+ [10712.661365168819,2289.2054098961353],
+ [10811.96136516882,2454.805409896135],
+ [10911.26136516882,2289.2054098961353],
+ [10811.96136516882,2289.2054098961353],
+ [10712.661365168819,2454.805409896135],
+ [10712.661365168819,2620.405409896135],
+ [10811.96136516882,2786.005409896135],
+ [10911.26136516882,2620.405409896135],
+ [10911.26136516882,2786.005409896135],
+ [11010.561365168822,2620.405409896135],
+ [10911.26136516882,2454.805409896135],
+ [10811.96136516882,2620.405409896135],
+ [10712.661365168819,2786.005409896135],
+ [10811.96136516882,2951.605409896135],
+ [10911.26136516882,2951.605409896135],
+ [10811.96136516882,3117.205409896135],
+ [10712.661365168819,2951.605409896135],
+ [10613.361365168817,2951.605409896135],
+ [10514.061365168816,2951.605409896135],
+ [10414.761365168815,3117.205409896135],
+ [10414.761365168815,2951.605409896135],
+ [10315.461365168814,2786.005409896135],
+ [10216.161365168813,2620.405409896135],
+ [10216.161365168813,2786.005409896135],
+ [10315.461365168814,2951.605409896135],
+ [10315.461365168814,3117.205409896135],
+ [10216.161365168813,3117.205409896135],
+ [10116.861365168812,3117.205409896135],
+ [10017.56136516881,3282.8054098961347],
+ [9918.26136516881,3448.4054098961346],
+ [9818.961365168809,3448.4054098961346],
+ [9818.961365168809,3614.0054098961346],
+ [9719.661365168808,3448.4054098961346],
+ [9818.961365168809,3282.8054098961347],
+ [9719.661365168808,3117.205409896135],
+ [9620.361365168807,2951.605409896135],
+ [9521.061365168805,3117.205409896135],
+ [9521.061365168805,3282.8054098961347],
+ [9421.761365168804,3117.205409896135],
+ [9421.761365168804,3282.8054098961347],
+ [9322.461365168803,3117.205409896135],
+ [9421.761365168804,2951.605409896135],
+ [9322.461365168803,2951.605409896135],
+ [9223.161365168802,2786.005409896135],
+ [9322.461365168803,2620.405409896135],
+ [9421.761365168804,2454.805409896135],
+ [9521.061365168805,2289.2054098961353],
+ [9421.761365168804,2123.6054098961354],
+ [9421.761365168804,1958.0054098961352],
+ [9421.761365168804,1792.405409896135],
+ [9521.061365168805,1626.805409896135],
+ [9421.761365168804,1626.805409896135],
+ [9322.461365168803,1792.405409896135],
+ [9322.461365168803,1626.805409896135],
+ [9322.461365168803,1461.2054098961348],
+ [9421.761365168804,1461.2054098961348],
+ [9521.061365168805,1295.6054098961347],
+ [9421.761365168804,1130.0054098961346],
+ [9322.461365168803,964.4054098961345],
+ [9223.161365168802,964.4054098961345],
+ [9223.161365168802,798.8054098961346],
+ [9322.461365168803,633.2054098961347],
+ [9421.761365168804,798.8054098961346],
+ [9421.761365168804,633.2054098961347],
+ [9521.061365168805,633.2054098961347],
+ [9421.761365168804,467.60540989613474],
+ [9421.761365168804,302.0054098961348],
+ [9322.461365168803,136.40540989613478],
+ [9223.161365168802,302.0054098961348],
+ [9123.861365168801,302.0054098961348],
+ [9024.5613651688,136.40540989613478],
+ [9123.861365168801,136.40540989613478],
+ [9223.161365168802,136.40540989613478],
+ [9322.461365168803,302.0054098961348],
+ [9421.761365168804,136.40540989613478],
+ [9521.061365168805,136.40540989613478],
+ [9620.361365168807,136.40540989613478],
+ [9620.361365168807,302.0054098961348],
+ [9521.061365168805,302.0054098961348],
+ [9521.061365168805,467.60540989613474],
+ [9620.361365168807,467.60540989613474],
+ [9719.661365168808,302.0054098961348],
+ [9719.661365168808,136.40540989613478],
+ [9818.961365168809,136.40540989613478],
+ [9918.26136516881,136.40540989613478],
+ [10017.56136516881,136.40540989613478],
+ [366.07287160549004,5394.185440937868],
+ [465.37287160549005,5394.185440937868],
+ [465.37287160549005,5559.785440937868],
+ [366.0728716054901,5559.785440937868],
+ [366.0728716054901,5725.385440937867],
+ [266.77287160549014,5725.385440937867],
+ [167.47287160549016,5559.785440937868],
+ [266.77287160549014,5559.785440937868],
+ [266.77287160549014,5394.185440937868],
+ [266.77287160549014,5228.585440937869],
+ [167.47287160549016,5394.185440937868],
+ [68.17287160549016,5228.585440937869],
+ [167.47287160549013,5062.9854409378695],
+ [68.17287160549013,4897.38544093787],
+ [167.47287160549013,4731.785440937871],
+ [266.77287160549014,4731.785440937871],
+ [167.47287160549016,4566.185440937871],
+ [68.17287160549016,4566.185440937871],
+ [68.17287160549016,4731.785440937871],
+ [167.47287160549013,4897.38544093787],
+ [68.17287160549013,5062.9854409378695],
+ [167.47287160549013,5228.585440937869],
+ [266.77287160549014,5062.9854409378695],
+ [366.0728716054901,4897.38544093787],
+ [266.77287160549014,4897.38544093787],
+ [366.0728716054901,4731.785440937871],
+ [465.37287160549005,4897.38544093787],
+ [366.0728716054901,5062.9854409378695],
+ [465.37287160549005,5062.9854409378695],
+ [366.0728716054901,5228.585440937869],
+ [465.37287160549005,5228.585440937869],
+ [564.6728716054901,5394.185440937868],
+ [663.9728716054901,5228.585440937869],
+ [564.6728716054901,5062.9854409378695],
+ [663.9728716054901,4897.38544093787],
+ [763.2728716054902,4731.785440937871],
+ [862.5728716054903,4566.185440937871],
+ [961.8728716054903,4731.785440937871],
+ [862.5728716054903,4731.785440937871],
+ [961.8728716054903,4566.185440937871],
+ [862.5728716054903,4400.585440937872],
+ [961.8728716054903,4234.985440937872],
+ [1061.1728716054904,4400.585440937872],
+ [1160.4728716054904,4234.985440937872],
+ [1160.4728716054904,4400.585440937872],
+ [1259.7728716054903,4234.985440937872],
+ [1359.0728716054903,4069.3854409378723],
+ [1458.3728716054902,4069.3854409378723],
+ [1557.6728716054902,4234.985440937872],
+ [1656.9728716054901,4400.585440937872],
+ [1557.6728716054902,4400.585440937872],
+ [1458.3728716054902,4400.585440937872],
+ [1359.0728716054903,4566.185440937871],
+ [1359.0728716054903,4731.785440937871],
+ [1259.7728716054903,4731.785440937871],
+ [1359.0728716054903,4897.38544093787],
+ [1458.3728716054902,4731.785440937871],
+ [1458.3728716054902,4897.38544093787],
+ [1359.0728716054903,5062.9854409378695],
+ [1259.7728716054903,5228.585440937869],
+ [1259.7728716054903,5062.9854409378695],
+ [1259.7728716054903,4897.38544093787],
+ [1160.4728716054904,5062.9854409378695],
+ [1160.4728716054904,5228.585440937869],
+ [1061.1728716054904,5228.585440937869],
+ [1061.1728716054904,5062.9854409378695],
+ [961.8728716054903,5228.585440937869],
+ [862.5728716054903,5062.9854409378695],
+ [961.8728716054903,5062.9854409378695],
+ [961.8728716054903,4897.38544093787],
+ [1061.1728716054904,4897.38544093787],
+ [1160.4728716054904,4731.785440937871],
+ [1259.7728716054903,4566.185440937871],
+ [1359.0728716054903,4400.585440937872],
+ [1458.3728716054902,4566.185440937871],
+ [1557.6728716054902,4566.185440937871],
+ [1656.9728716054901,4731.785440937871],
+ [1557.6728716054902,4897.38544093787],
+ [1458.3728716054902,5062.9854409378695],
+ [1557.6728716054902,5228.585440937869],
+ [1656.9728716054901,5062.9854409378695],
+ [1756.27287160549,5062.9854409378695],
+ [1756.27287160549,4897.38544093787],
+ [1855.57287160549,5062.9854409378695],
+ [1954.87287160549,4897.38544093787],
+ [2054.17287160549,5062.9854409378695],
+ [1954.87287160549,5062.9854409378695],
+ [2054.17287160549,5228.585440937869],
+ [2153.4728716054897,5228.585440937869],
+ [2252.7728716054894,5062.9854409378695],
+ [2352.072871605489,5228.585440937869],
+ [2451.372871605489,5394.185440937868],
+ [2352.072871605489,5394.185440937868],
+ [2252.7728716054894,5228.585440937869],
+ [2153.4728716054897,5062.9854409378695],
+ [2153.4728716054897,4897.38544093787],
+ [2252.7728716054894,4897.38544093787],
+ [2352.072871605489,4731.785440937871],
+ [2252.7728716054894,4731.785440937871],
+ [2153.4728716054897,4731.785440937871],
+ [2054.17287160549,4566.185440937871],
+ [1954.87287160549,4731.785440937871],
+ [1855.57287160549,4897.38544093787],
+ [1756.27287160549,4731.785440937871],
+ [1855.57287160549,4731.785440937871],
+ [1855.57287160549,4566.185440937871],
+ [1756.27287160549,4566.185440937871],
+ [1656.9728716054901,4566.185440937871],
+ [1557.6728716054902,4731.785440937871],
+ [1656.9728716054901,4897.38544093787],
+ [1557.6728716054902,5062.9854409378695],
+ [1458.3728716054902,5228.585440937869],
+ [1359.0728716054903,5228.585440937869],
+ [1259.7728716054903,5394.185440937868],
+ [1259.7728716054903,5559.785440937868],
+ [1160.4728716054904,5559.785440937868],
+ [1061.1728716054904,5559.785440937868],
+ [1160.4728716054904,5725.385440937867],
+ [1259.7728716054903,5725.385440937867],
+ [1359.0728716054903,5559.785440937868],
+ [1458.3728716054902,5725.385440937867],
+ [1458.3728716054902,5559.785440937868],
+ [1359.0728716054903,5725.385440937867],
+ [1259.7728716054903,5890.985440937867],
+ [1359.0728716054903,5890.985440937867],
+ [1259.7728716054903,6056.585440937866],
+ [1359.0728716054903,6222.185440937866],
+ [1458.3728716054902,6222.185440937866],
+ [1458.3728716054902,6387.785440937865],
+ [1557.6728716054902,6222.185440937866],
+ [1557.6728716054902,6387.785440937865],
+ [1656.9728716054901,6222.185440937866],
+ [1756.27287160549,6056.585440937866],
+ [1855.57287160549,5890.985440937867],
+ [1756.27287160549,5890.985440937867],
+ [1656.9728716054901,6056.585440937866],
+ [1557.6728716054902,5890.985440937867],
+ [1458.3728716054902,5890.985440937867],
+ [1359.0728716054903,6056.585440937866],
+ [1259.7728716054903,6222.185440937866],
+ [1160.4728716054904,6056.585440937866],
+ [1061.1728716054904,5890.985440937867],
+ [1061.1728716054904,6056.585440937866],
+ [1160.4728716054904,6222.185440937866],
+ [1061.1728716054904,6222.185440937866],
+ [961.8728716054903,6222.185440937866],
+ [961.8728716054903,6056.585440937866],
+ [961.8728716054903,5890.985440937867],
+ [961.8728716054903,5725.385440937867],
+ [862.5728716054903,5559.785440937868],
+ [763.2728716054902,5725.385440937867],
+ [862.5728716054903,5725.385440937867],
+ [763.2728716054902,5890.985440937867],
+ [663.9728716054901,5725.385440937867],
+ [763.2728716054902,5559.785440937868],
+ [763.2728716054902,5394.185440937868],
+ [862.5728716054903,5228.585440937869],
+ [961.8728716054903,5394.185440937868],
+ [1061.1728716054904,5394.185440937868],
+ [961.8728716054903,5559.785440937868],
+ [862.5728716054903,5394.185440937868],
+ [763.2728716054902,5228.585440937869],
+ [663.9728716054901,5062.9854409378695],
+ [763.2728716054902,5062.9854409378695],
+ [763.2728716054902,4897.38544093787],
+ [663.9728716054901,4731.785440937871],
+ [564.6728716054901,4731.785440937871],
+ [465.37287160549005,4566.185440937871],
+ [366.0728716054901,4566.185440937871],
+ [465.37287160549005,4731.785440937871],
+ [564.6728716054901,4566.185440937871],
+ [465.37287160549005,4400.585440937872],
+ [366.0728716054901,4400.585440937872],
+ [266.77287160549014,4234.985440937872],
+ [167.47287160549016,4234.985440937872],
+ [266.77287160549014,4400.585440937872],
+ [266.77287160549014,4566.185440937871],
+ [167.47287160549016,4400.585440937872],
+ [68.17287160549016,4234.985440937872],
+ [167.47287160549013,4069.3854409378723],
+ [68.17287160549013,3903.7854409378724],
+ [68.17287160549013,4069.3854409378723],
+ [167.47287160549013,3903.7854409378724],
+ [266.77287160549014,3903.7854409378724],
+ [366.0728716054901,3738.1854409378725],
+ [266.77287160549014,3738.1854409378725],
+ [266.77287160549014,3572.5854409378726],
+ [167.47287160549016,3406.9854409378727],
+ [167.47287160549016,3241.3854409378728],
+ [266.77287160549014,3241.3854409378728],
+ [266.77287160549014,3406.9854409378727],
+ [366.0728716054901,3572.5854409378726],
+ [465.37287160549005,3738.1854409378725],
+ [465.37287160549005,3903.7854409378724],
+ [366.0728716054901,4069.3854409378723],
+ [366.0728716054901,4234.985440937872],
+ [465.37287160549005,4234.985440937872],
+ [564.6728716054901,4069.3854409378723],
+ [465.37287160549005,4069.3854409378723],
+ [564.6728716054901,4234.985440937872],
+ [663.9728716054901,4069.3854409378723],
+ [663.9728716054901,4234.985440937872],
+ [663.9728716054901,4400.585440937872],
+ [763.2728716054902,4566.185440937871],
+ [763.2728716054902,4400.585440937872],
+ [663.9728716054901,4566.185440937871],
+ [564.6728716054901,4400.585440937872],
+ [19431.915041401327,3495.506142643713],
+ [19332.61504140133,3661.1061426437127],
+ [19431.915041401327,3661.1061426437127],
+ [19531.215041401327,3661.1061426437127],
+ [19630.515041401326,3495.506142643713],
+ [19630.515041401326,3661.1061426437127],
+ [19729.815041401325,3826.7061426437126],
+ [19630.515041401326,3826.7061426437126],
+ [19729.815041401325,3992.3061426437125],
+ [19630.515041401326,3992.3061426437125],
+ [19630.515041401326,4157.906142643712],
+ [19630.515041401326,4323.506142643711],
+ [19531.215041401327,4157.906142643712],
+ [19431.915041401327,4323.506142643711],
+ [19531.215041401327,4489.106142643711],
+ [19431.915041401327,4654.70614264371],
+ [19332.61504140133,4654.70614264371],
+ [19332.61504140133,4820.30614264371],
+ [19332.61504140133,4985.906142643709],
+ [19233.31504140133,4985.906142643709],
+ [19134.01504140133,5151.506142643709],
+ [19034.71504140133,5151.506142643709],
+ [19134.01504140133,5317.106142643708],
+ [19034.71504140133,5317.106142643708],
+ [19034.71504140133,5482.706142643708],
+ [18935.41504140133,5648.306142643707],
+ [18836.115041401332,5813.9061426437065],
+ [18836.115041401332,5979.506142643706],
+ [18935.41504140133,5979.506142643706],
+ [19034.71504140133,6145.106142643705],
+ [19034.71504140133,5979.506142643706],
+ [19034.71504140133,5813.9061426437065],
+ [19134.01504140133,5648.306142643707],
+ [19233.31504140133,5648.306142643707],
+ [19134.01504140133,5813.9061426437065],
+ [19134.01504140133,5979.506142643706],
+ [19233.31504140133,5813.9061426437065],
+ [19233.31504140133,5979.506142643706],
+ [19332.61504140133,6145.106142643705],
+ [19332.61504140133,6310.706142643705],
+ [19233.31504140133,6310.706142643705],
+ [19233.31504140133,6476.306142643704],
+ [19332.61504140133,6476.306142643704],
+ [19431.915041401327,6641.906142643704],
+ [19332.61504140133,6807.506142643703],
+ [19332.61504140133,6641.906142643704],
+ [19431.915041401327,6476.306142643704],
+ [19431.915041401327,6310.706142643705],
+ [19531.215041401327,6145.106142643705],
+ [19431.915041401327,5979.506142643706],
+ [19431.915041401327,6145.106142643705],
+ [19531.215041401327,5979.506142643706],
+ [19630.515041401326,5813.9061426437065],
+ [19630.515041401326,5979.506142643706],
+ [19729.815041401325,5813.9061426437065],
+ [19829.115041401325,5979.506142643706],
+ [19729.815041401325,5979.506142643706],
+ [19729.815041401325,6145.106142643705],
+ [19729.815041401325,6310.706142643705],
+ [19630.515041401326,6476.306142643704],
+ [19729.815041401325,6476.306142643704],
+ [19630.515041401326,6310.706142643705],
+ [19531.215041401327,6310.706142643705],
+ [19531.215041401327,6476.306142643704],
+ [19630.515041401326,6641.906142643704],
+ [19729.815041401325,6807.506142643703],
+ [19829.115041401325,6973.106142643703],
+ [19928.415041401324,6973.106142643703],
+ [19928.415041401324,7138.706142643702],
+ [20027.715041401323,7138.706142643702],
+ [20027.715041401323,7304.306142643702],
+ [19928.415041401324,7304.306142643702],
+ [19829.115041401325,7304.306142643702],
+ [19829.115041401325,7469.906142643701],
+ [19928.415041401324,7469.906142643701],
+ [19928.415041401324,7635.5061426437005],
+ [19928.415041401324,7801.1061426437],
+ [20027.715041401323,7635.5061426437005],
+ [20027.715041401323,7801.1061426437],
+ [20127.015041401322,7801.1061426437],
+ [20226.31504140132,7801.1061426437],
+ [20325.61504140132,7801.1061426437],
+ [20226.31504140132,7635.5061426437005],
+ [20226.31504140132,7469.906142643701],
+ [20226.31504140132,7304.306142643702],
+ [20127.015041401322,7304.306142643702],
+ [20027.715041401323,7469.906142643701],
+ [20127.015041401322,7469.906142643701],
+ [20127.015041401322,7635.5061426437005],
+ [2748.790306732237,2362.9553147492866],
+ [2848.0903067322365,2528.5553147492865],
+ [2748.790306732237,2694.1553147492864],
+ [2649.490306732237,2859.7553147492863],
+ [2748.790306732237,3025.355314749286],
+ [2848.0903067322365,2859.7553147492863],
+ [2848.0903067322365,2694.1553147492864],
+ [2947.3903067322362,2694.1553147492864],
+ [3046.690306732236,2859.7553147492863],
+ [3145.9903067322357,2694.1553147492864],
+ [3145.9903067322357,2528.5553147492865],
+ [3046.690306732236,2694.1553147492864],
+ [3145.9903067322357,2859.7553147492863],
+ [3046.690306732236,3025.355314749286],
+ [3145.9903067322357,3025.355314749286],
+ [3245.2903067322354,3190.955314749286],
+ [3245.2903067322354,3356.555314749286],
+ [3344.590306732235,3522.155314749286],
+ [3443.890306732235,3356.555314749286],
+ [3543.1903067322346,3356.555314749286],
+ [3642.4903067322343,3190.955314749286],
+ [3741.790306732234,3025.355314749286],
+ [3741.790306732234,2859.7553147492863],
+ [3841.090306732234,3025.355314749286],
+ [3841.090306732234,3190.955314749286],
+ [3741.790306732234,3190.955314749286],
+ [3642.4903067322343,3025.355314749286],
+ [3543.1903067322346,3025.355314749286],
+ [3543.1903067322346,2859.7553147492863],
+ [3443.890306732235,3025.355314749286],
+ [3443.890306732235,3190.955314749286],
+ [3543.1903067322346,3190.955314749286],
+ [3642.4903067322343,3356.555314749286],
+ [3543.1903067322346,3522.155314749286],
+ [3443.890306732235,3687.755314749286],
+ [3443.890306732235,3853.3553147492858],
+ [3344.590306732235,3687.755314749286],
+ [3245.2903067322354,3853.3553147492858],
+ [3245.2903067322354,3687.755314749286],
+ [3145.9903067322357,3687.755314749286],
+ [3046.690306732236,3853.3553147492858],
+ [3145.9903067322357,4018.9553147492857],
+ [3145.9903067322357,3853.3553147492858],
+ [3046.690306732236,3687.755314749286],
+ [3145.9903067322357,3522.155314749286],
+ [3145.9903067322357,3356.555314749286],
+ [3145.9903067322357,3190.955314749286],
+ [3046.690306732236,3190.955314749286],
+ [3046.690306732236,3356.555314749286],
+ [2947.3903067322362,3356.555314749286],
+ [2848.0903067322365,3190.955314749286],
+ [2947.3903067322362,3025.355314749286],
+ [2848.0903067322365,3025.355314749286],
+ [2748.790306732237,2859.7553147492863],
+ [2649.490306732237,2694.1553147492864],
+ [2748.790306732237,2528.5553147492865],
+ [2848.0903067322365,2362.9553147492866],
+ [2748.790306732237,2197.3553147492867],
+ [2649.490306732237,2362.9553147492866],
+ [2649.490306732237,2197.3553147492867],
+ [2550.1903067322373,2362.9553147492866],
+ [2450.8903067322376,2362.9553147492866],
+ [2351.590306732238,2528.5553147492865],
+ [2252.290306732238,2528.5553147492865],
+ [2351.590306732238,2362.9553147492866],
+ [2252.290306732238,2197.3553147492867],
+ [2351.590306732238,2197.3553147492867],
+ [2351.590306732238,2031.7553147492865],
+ [2351.590306732238,1866.1553147492864],
+ [2252.290306732238,1866.1553147492864],
+ [2351.590306732238,1700.5553147492863],
+ [2450.8903067322376,1534.9553147492861],
+ [2351.590306732238,1369.355314749286],
+ [2252.290306732238,1203.7553147492858],
+ [2252.290306732238,1369.355314749286],
+ [2252.290306732238,1534.9553147492861],
+ [2152.9903067322384,1369.355314749286],
+ [2053.6903067322387,1369.355314749286],
+ [1954.3903067322387,1203.7553147492858],
+ [1855.0903067322388,1203.7553147492858],
+ [1755.7903067322388,1038.1553147492857],
+ [1656.4903067322389,1038.1553147492857],
+ [1557.190306732239,872.5553147492857],
+ [1457.890306732239,1038.1553147492857],
+ [1457.890306732239,872.5553147492857],
+ [1457.890306732239,706.9553147492858],
+ [1557.190306732239,706.9553147492858],
+ [1656.4903067322389,872.5553147492857],
+ [1656.4903067322389,706.9553147492858],
+ [1755.7903067322388,706.9553147492858],
+ [1656.4903067322389,541.3553147492859],
+ [1557.190306732239,375.7553147492859],
+ [1656.4903067322389,210.1553147492859],
+ [1755.7903067322388,44.55531474928592],
+ [1656.4903067322389,44.55531474928592],
+ [1557.190306732239,210.1553147492859],
+ [1457.890306732239,210.1553147492859],
+ [1457.890306732239,44.55531474928592],
+ [1358.590306732239,210.1553147492859],
+ [1358.590306732239,375.75531474928584],
+ [1259.290306732239,210.15531474928585],
+ [1259.290306732239,375.75531474928584],
+ [1259.290306732239,541.3553147492859],
+ [1358.590306732239,706.9553147492858],
+ [1358.590306732239,872.5553147492857],
+ [1259.290306732239,706.9553147492858],
+ [1259.290306732239,872.5553147492857],
+ [1259.290306732239,1038.1553147492857],
+ [1358.590306732239,1203.7553147492858],
+ [1358.590306732239,1038.1553147492857],
+ [1457.890306732239,1203.7553147492858],
+ [1557.190306732239,1369.355314749286],
+ [1656.4903067322389,1203.7553147492858],
+ [1557.190306732239,1203.7553147492858],
+ [1557.190306732239,1038.1553147492857],
+ [17254.572515546668,1460.5807801244923],
+ [17353.872515546667,1626.1807801244925],
+ [17453.172515546667,1791.7807801244926],
+ [17552.472515546666,1791.7807801244926],
+ [17453.172515546667,1626.1807801244925],
+ [17353.872515546667,1791.7807801244926],
+ [17453.172515546667,1957.3807801244927],
+ [17353.872515546667,2122.980780124493],
+ [17453.172515546667,2288.580780124493],
+ [17353.872515546667,2454.1807801244927],
+ [17453.172515546667,2619.7807801244926],
+ [17552.472515546666,2619.7807801244926],
+ [17453.172515546667,2785.3807801244925],
+ [17353.872515546667,2619.7807801244926],
+ [17254.572515546668,2454.1807801244927],
+ [17254.572515546668,2288.580780124493],
+ [17353.872515546667,2288.580780124493],
+ [17453.172515546667,2122.980780124493],
+ [17552.472515546666,2288.580780124493],
+ [17552.472515546666,2454.1807801244927],
+ [17453.172515546667,2454.1807801244927],
+ [4447.67624466283,4761.1416826913],
+ [4546.97624466283,4595.541682691301],
+ [4546.97624466283,4429.941682691301],
+ [4447.67624466283,4429.941682691301],
+ [4447.67624466283,4595.541682691301],
+ [4348.37624466283,4595.541682691301],
+ [4249.07624466283,4595.541682691301],
+ [4348.37624466283,4761.1416826913],
+ [4249.07624466283,4761.1416826913],
+ [4348.37624466283,4926.7416826912995],
+ [4348.37624466283,5092.341682691299],
+ [4447.67624466283,5257.941682691298],
+ [4546.97624466283,5257.941682691298],
+ [4646.27624466283,5092.341682691299],
+ [4546.97624466283,5092.341682691299],
+ [4646.27624466283,4926.7416826912995],
+ [4646.27624466283,4761.1416826913],
+ [4546.97624466283,4761.1416826913],
+ [4646.27624466283,4595.541682691301],
+ [4745.5762446628305,4595.541682691301],
+ [4646.27624466283,4429.941682691301],
+ [4745.5762446628305,4429.941682691301],
+ [4844.876244662831,4595.541682691301],
+ [4745.5762446628305,4761.1416826913],
+ [4745.5762446628305,4926.7416826912995],
+ [4844.876244662831,4761.1416826913],
+ [4944.176244662831,4761.1416826913],
+ [5043.476244662831,4926.7416826912995],
+ [5043.476244662831,4761.1416826913],
+ [5142.776244662831,4926.7416826912995],
+ [5142.776244662831,4761.1416826913],
+ [5242.076244662831,4595.541682691301],
+ [5142.776244662831,4595.541682691301],
+ [5242.076244662831,4429.941682691301],
+ [5242.076244662831,4264.341682691302],
+ [5142.776244662831,4429.941682691301],
+ [5043.476244662831,4595.541682691301],
+ [5043.476244662831,4429.941682691301],
+ [5043.476244662831,4264.341682691302],
+ [5142.776244662831,4098.741682691302],
+ [5043.476244662831,4098.741682691302],
+ [4944.176244662831,3933.1416826913023],
+ [4944.176244662831,4098.741682691302],
+ [4944.176244662831,4264.341682691302],
+ [4844.876244662831,4098.741682691302],
+ [4745.5762446628305,4264.341682691302],
+ [4646.27624466283,4098.741682691302],
+ [4546.97624466283,3933.1416826913023],
+ [4447.67624466283,4098.741682691302],
+ [4546.97624466283,4264.341682691302],
+ [4447.67624466283,4264.341682691302],
+ [4546.97624466283,4098.741682691302],
+ [4646.27624466283,3933.1416826913023],
+ [4546.97624466283,3767.5416826913024],
+ [4447.67624466283,3601.9416826913025],
+ [4447.67624466283,3767.5416826913024],
+ [4348.37624466283,3767.5416826913024],
+ [4348.37624466283,3933.1416826913023],
+ [4249.07624466283,3767.5416826913024],
+ [4249.07624466283,3933.1416826913023],
+ [4149.776244662829,3933.1416826913023],
+ [4050.4762446628297,4098.741682691302],
+ [4050.4762446628297,3933.1416826913023],
+ [3951.17624466283,3933.1416826913023],
+ [3951.17624466283,4098.741682691302],
+ [3851.8762446628302,4264.341682691302],
+ [3851.8762446628302,4098.741682691302],
+ [3752.5762446628305,4098.741682691302],
+ [3653.276244662831,4264.341682691302],
+ [3553.976244662831,4429.941682691301],
+ [3553.976244662831,4595.541682691301],
+ [3454.6762446628313,4429.941682691301],
+ [3553.976244662831,4264.341682691302],
+ [3653.276244662831,4429.941682691301],
+ [3752.5762446628305,4264.341682691302],
+ [3752.5762446628305,4429.941682691301],
+ [3851.8762446628302,4595.541682691301],
+ [3851.8762446628302,4429.941682691301],
+ [3951.17624466283,4429.941682691301],
+ [4050.4762446628297,4264.341682691302],
+ [4149.776244662829,4098.741682691302],
+ [4249.07624466283,4264.341682691302],
+ [4348.37624466283,4098.741682691302],
+ [4447.67624466283,3933.1416826913023],
+ [9574.088902135607,7352.26293905581],
+ [9474.788902135606,7352.26293905581],
+ [9375.488902135605,7186.662939055811],
+ [9474.788902135606,7021.0629390558115],
+ [9574.088902135607,7021.0629390558115],
+ [9474.788902135606,7186.662939055811],
+ [9574.088902135607,7186.662939055811],
+ [9673.388902135608,7021.0629390558115],
+ [9673.388902135608,6855.462939055812],
+ [9772.68890213561,6689.862939055813],
+ [9673.388902135608,6689.862939055813],
+ [9772.68890213561,6524.262939055813],
+ [9871.98890213561,6358.662939055814],
+ [9971.288902135611,6524.262939055813],
+ [10070.588902135612,6358.662939055814],
+ [10070.588902135612,6193.062939055814],
+ [9971.288902135611,6027.462939055815],
+ [9971.288902135611,5861.862939055815],
+ [9871.98890213561,5861.862939055815],
+ [9871.98890213561,5696.262939055816],
+ [9971.288902135611,5530.662939055816],
+ [10070.588902135612,5530.662939055816],
+ [10070.588902135612,5696.262939055816],
+ [10169.888902135614,5861.862939055815],
+ [10169.888902135614,5696.262939055816],
+ [10070.588902135612,5861.862939055815],
+ [10169.888902135614,6027.462939055815],
+ [10169.888902135614,6193.062939055814],
+ [10269.188902135615,6027.462939055815],
+ [10269.188902135615,5861.862939055815],
+ [10368.488902135616,6027.462939055815],
+ [10269.188902135615,6193.062939055814],
+ [10269.188902135615,6358.662939055814],
+ [10169.888902135614,6358.662939055814],
+ [10070.588902135612,6524.262939055813],
+ [10070.588902135612,6689.862939055813],
+ [9971.288902135611,6855.462939055812],
+ [9971.288902135611,7021.0629390558115],
+ [10070.588902135612,7186.662939055811],
+ [10169.888902135614,7186.662939055811],
+ [10269.188902135615,7186.662939055811],
+ [10169.888902135614,7352.26293905581],
+ [10070.588902135612,7352.26293905581],
+ [10169.888902135614,7517.86293905581],
+ [10169.888902135614,7683.462939055809],
+ [10269.188902135615,7517.86293905581],
+ [10368.488902135616,7683.462939055809],
+ [10467.788902135617,7683.462939055809],
+ [10368.488902135616,7517.86293905581],
+ [10269.188902135615,7352.26293905581],
+ [10368.488902135616,7352.26293905581],
+ [10368.488902135616,7186.662939055811],
+ [10368.488902135616,7021.0629390558115],
+ [10368.488902135616,6855.462939055812],
+ [10269.188902135615,6855.462939055812],
+ [10169.888902135614,6855.462939055812],
+ [10169.888902135614,7021.0629390558115],
+ [10070.588902135612,7021.0629390558115],
+ [10070.588902135612,6855.462939055812],
+ [10169.888902135614,6689.862939055813],
+ [10269.188902135615,6689.862939055813],
+ [10169.888902135614,6524.262939055813],
+ [10269.188902135615,6524.262939055813],
+ [10368.488902135616,6524.262939055813],
+ [10368.488902135616,6358.662939055814],
+ [10467.788902135617,6358.662939055814],
+ [10467.788902135617,6193.062939055814],
+ [10567.088902135618,6358.662939055814],
+ [10567.088902135618,6193.062939055814],
+ [10666.388902135619,6193.062939055814],
+ [10666.388902135619,6358.662939055814],
+ [10567.088902135618,6524.262939055813],
+ [10467.788902135617,6524.262939055813],
+ [10567.088902135618,6689.862939055813],
+ [10467.788902135617,6855.462939055812],
+ [10567.088902135618,7021.0629390558115],
+ [10467.788902135617,7021.0629390558115],
+ [10567.088902135618,6855.462939055812],
+ [10467.788902135617,6689.862939055813],
+ [10368.488902135616,6689.862939055813],
+ [1073.6944354374714,1154.3681204032646],
+ [974.3944354374713,1319.9681204032647],
+ [875.0944354374712,1319.9681204032647],
+ [775.7944354374712,1154.3681204032646],
+ [775.7944354374712,988.7681204032646],
+ [875.0944354374712,823.1681204032647],
+ [875.0944354374712,657.5681204032647],
+ [775.7944354374712,823.1681204032647],
+ [676.4944354374711,657.5681204032647],
+ [676.4944354374711,491.9681204032648],
+ [775.7944354374712,657.5681204032647],
+ [676.4944354374711,823.1681204032647],
+ [676.4944354374711,988.7681204032646],
+ [577.194435437471,823.1681204032647],
+ [577.194435437471,988.7681204032646],
+ [577.194435437471,1154.3681204032646],
+ [676.4944354374711,1319.9681204032647],
+ [577.194435437471,1319.9681204032647],
+ [477.89443543747103,1319.9681204032647],
+ [577.194435437471,1485.5681204032649],
+ [477.89443543747103,1651.168120403265],
+ [577.194435437471,1816.7681204032651],
+ [477.89443543747103,1816.7681204032651],
+ [378.5944354374711,1982.3681204032653],
+ [378.5944354374711,2147.9681204032654],
+ [279.2944354374711,2313.5681204032653],
+ [179.99443543747114,2147.9681204032654],
+ [80.69443543747114,2313.5681204032653],
+ [80.69443543747114,2479.168120403265],
+ [179.9944354374711,2644.768120403265],
+ [179.9944354374711,2479.168120403265],
+ [179.9944354374711,2313.5681204032653],
+ [80.69443543747111,2147.9681204032654],
+ [80.69443543747111,1982.3681204032653],
+ [179.9944354374711,1982.3681204032653],
+ [179.9944354374711,1816.7681204032651],
+ [80.69443543747111,1816.7681204032651],
+ [179.9944354374711,1651.168120403265],
+ [80.69443543747111,1485.5681204032649],
+ [80.69443543747111,1319.9681204032647],
+ [179.9944354374711,1154.3681204032646],
+ [80.69443543747111,1154.3681204032646],
+ [179.9944354374711,988.7681204032646],
+ [279.2944354374711,823.1681204032647],
+ [378.5944354374711,657.5681204032647],
+ [378.5944354374711,823.1681204032647],
+ [477.89443543747103,823.1681204032647],
+ [477.89443543747103,657.5681204032647],
+ [378.5944354374711,491.9681204032648],
+ [477.89443543747103,326.3681204032648],
+ [477.89443543747103,160.76812040326482],
+ [378.5944354374711,160.76812040326482],
+ [279.2944354374711,326.3681204032648],
+ [179.99443543747114,491.9681204032648],
+ [179.99443543747114,326.3681204032648],
+ [279.2944354374711,491.9681204032648],
+ [279.2944354374711,657.5681204032647],
+ [179.99443543747114,823.1681204032647],
+ [279.2944354374711,988.7681204032646],
+ [279.2944354374711,1154.3681204032646],
+ [378.5944354374711,1319.9681204032647],
+ [477.89443543747103,1485.5681204032649],
+ [577.194435437471,1651.168120403265],
+ [676.4944354374711,1651.168120403265],
+ [775.7944354374712,1816.7681204032651],
+ [676.4944354374711,1816.7681204032651],
+ [775.7944354374712,1651.168120403265],
+ [875.0944354374712,1651.168120403265],
+ [974.3944354374713,1651.168120403265],
+ [875.0944354374712,1485.5681204032649],
+ [775.7944354374712,1485.5681204032649],
+ [676.4944354374711,1485.5681204032649],
+ [775.7944354374712,1319.9681204032647],
+ [676.4944354374711,1154.3681204032646],
+ [3138.413562431697,2355.845602060523],
+ [3039.113562431697,2521.445602060523],
+ [3039.113562431697,2355.845602060523],
+ [3039.113562431697,2190.245602060523],
+ [3138.413562431697,2024.645602060523],
+ [3237.7135624316966,1859.045602060523],
+ [3237.7135624316966,2024.645602060523],
+ [3337.0135624316963,1859.045602060523],
+ [3337.0135624316963,1693.4456020605228],
+ [3436.313562431696,1527.8456020605227],
+ [3535.6135624316958,1693.4456020605228],
+ [3535.6135624316958,1859.045602060523],
+ [3634.9135624316955,2024.645602060523],
+ [3734.213562431695,2190.245602060523],
+ [3634.9135624316955,2190.245602060523],
+ [3535.6135624316958,2190.245602060523],
+ [3535.6135624316958,2355.845602060523],
+ [3535.6135624316958,2521.445602060523],
+ [3436.313562431696,2687.045602060523],
+ [3436.313562431696,2852.645602060523],
+ [3535.6135624316958,2687.045602060523],
+ [3634.9135624316955,2521.445602060523],
+ [3634.9135624316955,2355.845602060523],
+ [3734.213562431695,2355.845602060523],
+ [3833.513562431695,2190.245602060523],
+ [3932.8135624316947,2024.645602060523],
+ [3833.513562431695,1859.045602060523],
+ [3833.513562431695,1693.4456020605228],
+ [3734.213562431695,1859.045602060523],
+ [3734.213562431695,1693.4456020605228],
+ [3734.213562431695,1527.8456020605227],
+ [3634.9135624316955,1527.8456020605227],
+ [3634.9135624316955,1693.4456020605228],
+ [3535.6135624316958,1527.8456020605227],
+ [3634.9135624316955,1362.2456020605225],
+ [3535.6135624316958,1362.2456020605225],
+ [3436.313562431696,1196.6456020605224],
+ [3535.6135624316958,1196.6456020605224],
+ [3535.6135624316958,1031.0456020605222],
+ [3436.313562431696,1031.0456020605222],
+ [3535.6135624316958,865.4456020605222],
+ [3436.313562431696,865.4456020605222],
+ [3535.6135624316958,699.8456020605223],
+ [3634.9135624316955,699.8456020605223],
+ [3535.6135624316958,534.2456020605224],
+ [3436.313562431696,368.64560206052244],
+ [3436.313562431696,203.04560206052244],
+ [3337.0135624316963,37.445602060522454],
+ [3436.313562431696,37.445602060522454],
+ [3337.0135624316963,203.04560206052244],
+ [3237.7135624316966,37.445602060522454],
+ [3138.413562431697,37.445602060522454],
+ [3237.7135624316966,203.04560206052244],
+ [3337.0135624316963,368.6456020605224],
+ [3436.313562431696,534.2456020605224],
+ [3337.0135624316963,699.8456020605223],
+ [3237.7135624316966,534.2456020605224],
+ [3337.0135624316963,534.2456020605224],
+ [3436.313562431696,699.8456020605223],
+ [3337.0135624316963,865.4456020605222],
+ [3237.7135624316966,865.4456020605222],
+ [3337.0135624316963,1031.0456020605222],
+ [3237.7135624316966,1196.6456020605224],
+ [3138.413562431697,1362.2456020605225],
+ [3039.113562431697,1527.8456020605227],
+ [3138.413562431697,1527.8456020605227],
+ [3039.113562431697,1693.4456020605228],
+ [2939.8135624316974,1527.8456020605227],
+ [2840.5135624316977,1362.2456020605225],
+ [2840.5135624316977,1527.8456020605227],
+ [2840.5135624316977,1693.4456020605228],
+ [2939.8135624316974,1859.045602060523],
+ [2840.5135624316977,2024.645602060523],
+ [2840.5135624316977,1859.045602060523],
+ [2939.8135624316974,1693.4456020605228],
+ [3039.113562431697,1859.045602060523],
+ [3039.113562431697,2024.645602060523],
+ [2939.8135624316974,2190.245602060523],
+ [2939.8135624316974,2024.645602060523],
+ [16388.412117675925,1839.818884803299],
+ [16289.112117675924,1839.818884803299],
+ [16388.412117675925,1674.2188848032988],
+ [16487.712117675925,1508.6188848032987],
+ [16487.712117675925,1674.2188848032988],
+ [16388.412117675925,1508.6188848032987],
+ [16289.112117675924,1343.0188848032985],
+ [16289.112117675924,1508.6188848032987],
+ [16189.812117675923,1674.2188848032988],
+ [16090.512117675922,1839.818884803299],
+ [16090.512117675922,2005.418884803299],
+ [15991.212117675921,2171.018884803299],
+ [16090.512117675922,2336.618884803299],
+ [16090.512117675922,2502.218884803299],
+ [16090.512117675922,2667.8188848032987],
+ [15991.212117675921,2833.4188848032986],
+ [15991.212117675921,2999.0188848032985],
+ [15891.91211767592,3164.6188848032984],
+ [15891.91211767592,3330.2188848032984],
+ [15991.212117675921,3330.2188848032984],
+ [16090.512117675922,3330.2188848032984],
+ [16189.812117675923,3495.8188848032983],
+ [16289.112117675924,3495.8188848032983],
+ [16189.812117675923,3330.2188848032984],
+ [16189.812117675923,3164.6188848032984],
+ [16289.112117675924,3164.6188848032984],
+ [16388.412117675925,3164.6188848032984],
+ [16388.412117675925,3330.2188848032984],
+ [16487.712117675925,3330.2188848032984],
+ [16587.012117675924,3495.8188848032983],
+ [16587.012117675924,3661.418884803298],
+ [16686.312117675923,3661.418884803298],
+ [16785.612117675922,3661.418884803298],
+ [16884.91211767592,3661.418884803298],
+ [16984.21211767592,3661.418884803298],
+ [16884.91211767592,3827.018884803298],
+ [16884.91211767592,3992.618884803298],
+ [16984.21211767592,3827.018884803298],
+ [17083.51211767592,3661.418884803298],
+ [17182.81211767592,3495.8188848032983],
+ [17182.81211767592,3330.2188848032984],
+ [17282.11211767592,3164.6188848032984],
+ [17282.11211767592,3330.2188848032984],
+ [17182.81211767592,3164.6188848032984],
+ [17083.51211767592,3164.6188848032984],
+ [16984.21211767592,3330.2188848032984],
+ [16984.21211767592,3495.8188848032983],
+ [17083.51211767592,3330.2188848032984],
+ [16984.21211767592,3164.6188848032984],
+ [16984.21211767592,2999.0188848032985],
+ [17083.51211767592,2833.4188848032986],
+ [17083.51211767592,2667.8188848032987],
+ [17182.81211767592,2667.8188848032987],
+ [17182.81211767592,2833.4188848032986],
+ [17083.51211767592,2999.0188848032985],
+ [16984.21211767592,2833.4188848032986],
+ [16884.91211767592,2833.4188848032986],
+ [16884.91211767592,2999.0188848032985],
+ [16785.612117675922,2999.0188848032985],
+ [16884.91211767592,3164.6188848032984],
+ [16785.612117675922,3164.6188848032984],
+ [16686.312117675923,3164.6188848032984],
+ [16587.012117675924,3164.6188848032984],
+ [16587.012117675924,2999.0188848032985],
+ [16487.712117675925,3164.6188848032984],
+ [16587.012117675924,3330.2188848032984],
+ [16686.312117675923,3495.8188848032983],
+ [16686.312117675923,3330.2188848032984],
+ [16785.612117675922,3330.2188848032984],
+ [16884.91211767592,3495.8188848032983],
+ [16785.612117675922,3495.8188848032983],
+ [16884.91211767592,3330.2188848032984],
+ [1272.175991128079,3842.7700224365044],
+ [1371.475991128079,3842.7700224365044],
+ [1272.175991128079,3677.1700224365045],
+ [1172.875991128079,3511.5700224365046],
+ [1272.175991128079,3511.5700224365046],
+ [1172.875991128079,3345.9700224365047],
+ [1073.575991128079,3180.3700224365048],
+ [1073.575991128079,3014.770022436505],
+ [974.275991128079,3014.770022436505],
+ [874.9759911280789,3014.770022436505],
+ [775.6759911280789,2849.170022436505],
+ [775.6759911280789,3014.770022436505],
+ [775.6759911280789,3180.3700224365048],
+ [676.3759911280788,3345.9700224365047],
+ [676.3759911280788,3511.5700224365046],
+ [775.6759911280789,3677.1700224365045],
+ [676.3759911280788,3842.7700224365044],
+ [577.0759911280787,3842.7700224365044],
+ [577.0759911280787,3677.1700224365045],
+ [676.3759911280788,3677.1700224365045],
+ [775.6759911280789,3511.5700224365046],
+ [775.6759911280789,3345.9700224365047],
+ [874.9759911280789,3345.9700224365047],
+ [874.9759911280789,3180.3700224365048],
+ [974.275991128079,3180.3700224365048],
+ [974.275991128079,3345.9700224365047],
+ [1073.575991128079,3511.5700224365046],
+ [1073.575991128079,3677.1700224365045],
+ [1172.875991128079,3677.1700224365045],
+ [1172.875991128079,3842.7700224365044],
+ [1073.575991128079,3842.7700224365044],
+ [1172.875991128079,4008.3700224365043],
+ [1073.575991128079,4008.3700224365043],
+ [974.275991128079,3842.7700224365044],
+ [974.275991128079,4008.3700224365043],
+ [874.9759911280789,4008.3700224365043],
+ [775.6759911280789,4008.3700224365043],
+ [874.9759911280789,3842.7700224365044],
+ [974.275991128079,3677.1700224365045],
+ [974.275991128079,3511.5700224365046],
+ [1073.575991128079,3345.9700224365047],
+ [1172.875991128079,3180.3700224365048],
+ [1272.175991128079,3180.3700224365048],
+ [1272.175991128079,3345.9700224365047],
+ [1371.475991128079,3180.3700224365048],
+ [1470.7759911280789,3345.9700224365047],
+ [1371.475991128079,3345.9700224365047],
+ [1371.475991128079,3511.5700224365046],
+ [1470.7759911280789,3511.5700224365046],
+ [1570.0759911280788,3677.1700224365045],
+ [1470.7759911280789,3677.1700224365045],
+ [1570.0759911280788,3511.5700224365046],
+ [1669.3759911280788,3511.5700224365046],
+ [1669.3759911280788,3677.1700224365045],
+ [1768.6759911280787,3842.7700224365044],
+ [1669.3759911280788,3842.7700224365044],
+ [1768.6759911280787,4008.3700224365043],
+ [1867.9759911280787,3842.7700224365044],
+ [1967.2759911280787,3677.1700224365045],
+ [2066.5759911280784,3842.7700224365044],
+ [2165.875991128078,3677.1700224365045],
+ [2066.5759911280784,3511.5700224365046],
+ [2165.875991128078,3511.5700224365046],
+ [2066.5759911280784,3677.1700224365045],
+ [2165.875991128078,3842.7700224365044],
+ [2265.175991128078,4008.3700224365043],
+ [2364.4759911280776,4008.3700224365043],
+ [2265.175991128078,3842.7700224365044],
+ [2364.4759911280776,3677.1700224365045],
+ [2463.7759911280773,3842.7700224365044],
+ [2463.7759911280773,4008.3700224365043],
+ [2364.4759911280776,3842.7700224365044],
+ [6853.940039224797,6050.837897021371],
+ [6953.240039224797,6050.837897021371],
+ [7052.5400392247975,5885.237897021371],
+ [7052.5400392247975,5719.637897021372],
+ [7151.840039224798,5885.237897021371],
+ [7052.5400392247975,6050.837897021371],
+ [7052.5400392247975,6216.43789702137],
+ [7052.5400392247975,6382.03789702137],
+ [6953.240039224797,6382.03789702137],
+ [6953.240039224797,6216.43789702137],
+ [6853.940039224797,6216.43789702137],
+ [6853.940039224797,6382.03789702137],
+ [6754.640039224797,6216.43789702137],
+ [6754.640039224797,6382.03789702137],
+ [6754.640039224797,6547.637897021369],
+ [6754.640039224797,6713.237897021369],
+ [6655.340039224797,6713.237897021369],
+ [6754.640039224797,6878.837897021368],
+ [6853.940039224797,6713.237897021369],
+ [6853.940039224797,6878.837897021368],
+ [6953.240039224797,6713.237897021369],
+ [7052.5400392247975,6547.637897021369],
+ [7151.840039224798,6713.237897021369],
+ [7151.840039224798,6547.637897021369],
+ [7151.840039224798,6382.03789702137],
+ [7251.140039224798,6547.637897021369],
+ [7251.140039224798,6713.237897021369],
+ [7350.440039224798,6878.837897021368],
+ [7449.740039224798,6878.837897021368],
+ [7449.740039224798,6713.237897021369],
+ [7549.040039224798,6547.637897021369],
+ [7449.740039224798,6382.03789702137],
+ [7449.740039224798,6216.43789702137],
+ [7549.040039224798,6050.837897021371],
+ [7648.340039224799,6216.43789702137],
+ [7549.040039224798,6382.03789702137],
+ [7648.340039224799,6382.03789702137],
+ [7747.640039224799,6216.43789702137],
+ [7846.940039224799,6382.03789702137],
+ [7946.240039224799,6382.03789702137],
+ [7946.240039224799,6547.637897021369],
+ [7846.940039224799,6713.237897021369],
+ [7946.240039224799,6713.237897021369],
+ [8045.540039224799,6547.637897021369],
+ [8045.540039224799,6713.237897021369],
+ [7946.240039224799,6878.837897021368],
+ [7946.240039224799,7044.4378970213675],
+ [8045.540039224799,7210.037897021367],
+ [8144.8400392247995,7375.637897021366],
+ [8144.8400392247995,7541.237897021366],
+ [8045.540039224799,7375.637897021366],
+ [8144.8400392247995,7210.037897021367],
+ [8045.540039224799,7044.4378970213675],
+ [7946.240039224799,7210.037897021367],
+ [7846.940039224799,7210.037897021367],
+ [7946.240039224799,7375.637897021366],
+ [8045.540039224799,7541.237897021366],
+ [8144.8400392247995,7706.837897021365],
+ [8244.1400392248,7541.237897021366],
+ [8343.4400392248,7541.237897021366],
+ [8343.4400392248,7706.837897021365],
+ [8244.1400392248,7706.837897021365],
+ [4735.523842661975,3503.497768214323],
+ [4636.223842661975,3337.897768214323],
+ [4536.923842661975,3337.897768214323],
+ [4437.623842661975,3172.2977682143232],
+ [4338.323842661975,3172.2977682143232],
+ [4239.023842661974,3172.2977682143232],
+ [4338.323842661975,3006.6977682143233],
+ [4437.623842661975,2841.0977682143234],
+ [4338.323842661975,2675.4977682143235],
+ [4338.323842661975,2509.8977682143236],
+ [4239.023842661974,2675.4977682143235],
+ [4139.723842661974,2509.8977682143236],
+ [4040.4238426619745,2344.2977682143237],
+ [4139.723842661974,2178.697768214324],
+ [4239.023842661974,2178.697768214324],
+ [4139.723842661974,2344.2977682143237],
+ [4040.4238426619745,2178.697768214324],
+ [4139.723842661974,2013.0977682143237],
+ [4139.723842661974,1847.4977682143235],
+ [4239.023842661974,2013.0977682143237],
+ [4239.023842661974,1847.4977682143235],
+ [4338.323842661975,1847.4977682143235],
+ [4437.623842661975,1847.4977682143235],
+ [4536.923842661975,1681.8977682143234],
+ [4437.623842661975,1516.2977682143232],
+ [4536.923842661975,1516.2977682143232],
+ [4536.923842661975,1350.697768214323],
+ [4437.623842661975,1350.697768214323],
+ [4536.923842661975,1185.097768214323],
+ [4636.223842661975,1019.497768214323],
+ [4536.923842661975,853.897768214323],
+ [4636.223842661975,853.897768214323],
+ [4735.523842661975,688.2977682143231],
+ [4636.223842661975,522.6977682143232],
+ [4636.223842661975,357.09776821432325],
+ [4735.523842661975,357.09776821432325],
+ [4735.523842661975,522.6977682143232],
+ [4636.223842661975,688.2977682143231],
+ [4735.523842661975,853.897768214323],
+ [4834.8238426619755,853.897768214323],
+ [4735.523842661975,1019.497768214323],
+ [4735.523842661975,1185.097768214323],
+ [4735.523842661975,1350.697768214323],
+ [4834.8238426619755,1516.2977682143232],
+ [4735.523842661975,1516.2977682143232],
+ [4834.8238426619755,1350.697768214323],
+ [4834.8238426619755,1185.097768214323],
+ [4934.123842661976,1350.697768214323],
+ [5033.423842661976,1185.097768214323],
+ [5033.423842661976,1019.497768214323],
+ [5033.423842661976,853.897768214323],
+ [4934.123842661976,853.897768214323],
+ [4934.123842661976,1019.497768214323],
+ [4834.8238426619755,1019.497768214323],
+ [4934.123842661976,1185.097768214323],
+ [5033.423842661976,1350.697768214323],
+ [5132.723842661976,1350.697768214323],
+ [5132.723842661976,1185.097768214323],
+ [5232.023842661976,1019.497768214323],
+ [5232.023842661976,1185.097768214323],
+ [5331.323842661976,1019.497768214323],
+ [5430.623842661977,1019.497768214323],
+ [5529.923842661977,1185.097768214323],
+ [5430.623842661977,1350.697768214323],
+ [5430.623842661977,1516.2977682143232],
+ [5529.923842661977,1350.697768214323],
+ [5629.223842661977,1350.697768214323],
+ [5728.523842661977,1350.697768214323],
+ [5728.523842661977,1516.2977682143232],
+ [5728.523842661977,1681.8977682143234],
+ [5629.223842661977,1516.2977682143232],
+ [5529.923842661977,1516.2977682143232],
+ [5629.223842661977,1681.8977682143234],
+ [5529.923842661977,1681.8977682143234],
+ [5430.623842661977,1847.4977682143235],
+ [5331.323842661976,1847.4977682143235],
+ [5331.323842661976,2013.0977682143237],
+ [5232.023842661976,2178.697768214324],
+ [5132.723842661976,2013.0977682143237],
+ [5132.723842661976,2178.697768214324],
+ [5232.023842661976,2013.0977682143237],
+ [5232.023842661976,1847.4977682143235],
+ [5232.023842661976,1681.8977682143234],
+ [5331.323842661976,1681.8977682143234],
+ [5331.323842661976,1516.2977682143232],
+ [5331.323842661976,1350.697768214323],
+ [5232.023842661976,1350.697768214323],
+ [5232.023842661976,1516.2977682143232],
+ [5132.723842661976,1516.2977682143232],
+ [5132.723842661976,1681.8977682143234],
+ [5033.423842661976,1847.4977682143235],
+ [5132.723842661976,1847.4977682143235],
+ [5033.423842661976,2013.0977682143237],
+ [4934.123842661976,2178.697768214324],
+ [5033.423842661976,2344.2977682143237],
+ [4934.123842661976,2344.2977682143237],
+ [4834.8238426619755,2178.697768214324],
+ [4834.8238426619755,2344.2977682143237],
+ [4735.523842661975,2344.2977682143237],
+ [4636.223842661975,2344.2977682143237],
+ [4536.923842661975,2178.697768214324],
+ [4437.623842661975,2013.0977682143237],
+ [4338.323842661975,2178.697768214324],
+ [4437.623842661975,2344.2977682143237],
+ [4536.923842661975,2509.8977682143236],
+ [4636.223842661975,2675.4977682143235],
+ [4636.223842661975,2509.8977682143236],
+ [4536.923842661975,2675.4977682143235],
+ [4636.223842661975,2841.0977682143234],
+ [4536.923842661975,2841.0977682143234],
+ [4636.223842661975,3006.6977682143233],
+ [4735.523842661975,3172.2977682143232],
+ [4834.8238426619755,3006.6977682143233],
+ [4735.523842661975,2841.0977682143234],
+ [4735.523842661975,3006.6977682143233],
+ [4636.223842661975,3172.2977682143232],
+ [4735.523842661975,3337.897768214323],
+ [4834.8238426619755,3503.497768214323],
+ [4735.523842661975,3669.097768214323],
+ [4834.8238426619755,3834.697768214323],
+ [4834.8238426619755,3669.097768214323],
+ [4934.123842661976,3503.497768214323],
+ [5033.423842661976,3503.497768214323],
+ [5033.423842661976,3337.897768214323],
+ [4934.123842661976,3337.897768214323],
+ [4834.8238426619755,3172.2977682143232],
+ [4834.8238426619755,3337.897768214323],
+ [4934.123842661976,3172.2977682143232],
+ [5033.423842661976,3006.6977682143233],
+ [5132.723842661976,2841.0977682143234],
+ [5132.723842661976,3006.6977682143233],
+ [5232.023842661976,3172.2977682143232],
+ [5232.023842661976,3337.897768214323],
+ [5132.723842661976,3337.897768214323],
+ [5232.023842661976,3503.497768214323],
+ [5331.323842661976,3337.897768214323],
+ [5331.323842661976,3503.497768214323],
+ [5430.623842661977,3669.097768214323],
+ [5331.323842661976,3669.097768214323],
+ [5430.623842661977,3503.497768214323],
+ [5430.623842661977,3337.897768214323],
+ [5529.923842661977,3172.2977682143232],
+ [5529.923842661977,3337.897768214323],
+ [5629.223842661977,3337.897768214323],
+ [5728.523842661977,3337.897768214323],
+ [5728.523842661977,3503.497768214323],
+ [5827.823842661977,3503.497768214323],
+ [5927.1238426619775,3669.097768214323],
+ [6026.423842661978,3669.097768214323],
+ [6125.723842661978,3503.497768214323],
+ [6125.723842661978,3669.097768214323],
+ [6225.023842661978,3503.497768214323],
+ [6225.023842661978,3337.897768214323],
+ [6324.323842661978,3337.897768214323],
+ [6423.623842661978,3503.497768214323],
+ [6324.323842661978,3669.097768214323],
+ [6225.023842661978,3669.097768214323],
+ [6324.323842661978,3834.697768214323],
+ [6423.623842661978,3834.697768214323],
+ [6324.323842661978,4000.297768214323],
+ [6225.023842661978,3834.697768214323],
+ [6125.723842661978,3834.697768214323],
+ [6125.723842661978,4000.297768214323],
+ [6225.023842661978,4000.297768214323],
+ [6225.023842661978,4165.897768214322],
+ [6225.023842661978,4331.497768214322],
+ [6125.723842661978,4165.897768214322],
+ [6026.423842661978,4000.2977682143223],
+ [5927.1238426619775,4165.897768214322],
+ [6026.423842661978,4331.497768214322],
+ [6026.423842661978,4497.097768214321],
+ [5927.1238426619775,4497.097768214321],
+ [5827.823842661977,4662.697768214321],
+ [5728.523842661977,4828.29776821432],
+ [5827.823842661977,4828.29776821432],
+ [5927.1238426619775,4828.29776821432],
+ [5927.1238426619775,4662.697768214321],
+ [5827.823842661977,4497.097768214321],
+ [5927.1238426619775,4331.497768214322],
+ [5827.823842661977,4165.897768214322],
+ [5728.523842661977,4331.497768214322],
+ [5728.523842661977,4165.897768214322],
+ [5629.223842661977,4000.2977682143223],
+ [5629.223842661977,3834.6977682143224],
+ [5529.923842661977,3669.0977682143225],
+ [5629.223842661977,3503.4977682143226],
+ [5728.523842661977,3669.0977682143225],
+ [5827.823842661977,3669.0977682143225],
+ [5927.1238426619775,3834.6977682143224],
+ [5927.1238426619775,4000.2977682143223],
+ [6026.423842661978,4165.897768214322],
+ [6125.723842661978,4331.497768214322],
+ [6225.023842661978,4497.097768214321],
+ [6225.023842661978,4662.697768214321],
+ [6324.323842661978,4662.697768214321],
+ [6225.023842661978,4828.29776821432],
+ [6324.323842661978,4828.29776821432],
+ [6423.623842661978,4828.29776821432],
+ [6324.323842661978,4993.8977682143195],
+ [6225.023842661978,5159.497768214319],
+ [6125.723842661978,5159.497768214319],
+ [6026.423842661978,5325.097768214318],
+ [5927.1238426619775,5490.697768214318],
+ [6026.423842661978,5656.297768214317],
+ [5927.1238426619775,5821.897768214317],
+ [5927.1238426619775,5987.497768214316],
+ [6026.423842661978,5987.497768214316],
+ [6026.423842661978,5821.897768214317],
+ [5927.1238426619775,5656.297768214317],
+ [5827.823842661977,5656.297768214317],
+ [5827.823842661977,5490.697768214318],
+ [5728.523842661977,5490.697768214318],
+ [5629.223842661977,5325.097768214318],
+ [5629.223842661977,5159.497768214319],
+ [5529.923842661977,4993.8977682143195],
+ [5529.923842661977,5159.497768214319],
+ [5629.223842661977,4993.8977682143195],
+ [5629.223842661977,4828.29776821432],
+ [5529.923842661977,4662.697768214321],
+ [5430.623842661977,4828.29776821432],
+ [5529.923842661977,4828.29776821432],
+ [5629.223842661977,4662.697768214321],
+ [5728.523842661977,4662.697768214321],
+ [5629.223842661977,4497.097768214321],
+ [5728.523842661977,4497.097768214321],
+ [5827.823842661977,4331.497768214322],
+ [10216.161365168813,2951.605409896135],
+ [10116.861365168812,2951.605409896135],
+ [10017.56136516881,3117.205409896135],
+ [9918.26136516881,3117.205409896135],
+ [9818.961365168809,3117.205409896135],
+ [9719.661365168808,3282.8054098961347],
+ [9620.361365168807,3282.8054098961347],
+ [9620.361365168807,3117.205409896135],
+ [9521.061365168805,2951.605409896135],
+ [9521.061365168805,2786.005409896135],
+ [9620.361365168807,2786.005409896135],
+ [9719.661365168808,2786.005409896135],
+ [9818.961365168809,2620.405409896135],
+ [9918.26136516881,2786.005409896135],
+ [9818.961365168809,2951.605409896135],
+ [9818.961365168809,2786.005409896135],
+ [9719.661365168808,2620.405409896135],
+ [9719.661365168808,2454.805409896135],
+ [9620.361365168807,2289.2054098961353],
+ [9521.061365168805,2123.6054098961354],
+ [9620.361365168807,1958.0054098961352],
+ [9719.661365168808,2123.6054098961354],
+ [9818.961365168809,2289.2054098961353],
+ [9818.961365168809,2123.6054098961354],
+ [9818.961365168809,1958.0054098961352],
+ [9719.661365168808,1958.0054098961352],
+ [9620.361365168807,1792.405409896135],
+ [9620.361365168807,1626.805409896135],
+ [9521.061365168805,1461.2054098961348],
+ [9421.761365168804,1295.6054098961347],
+ [9521.061365168805,1130.0054098961346],
+ [9521.061365168805,964.4054098961345],
+ [9421.761365168804,964.4054098961345],
+ [9521.061365168805,798.8054098961346],
+ [9620.361365168807,798.8054098961346],
+ [9620.361365168807,964.4054098961345],
+ [9620.361365168807,1130.0054098961346],
+ [9620.361365168807,1295.6054098961347],
+ [9620.361365168807,1461.2054098961348],
+ [9719.661365168808,1295.6054098961347],
+ [9818.961365168809,1130.0054098961346],
+ [9918.26136516881,964.4054098961345],
+ [9818.961365168809,964.4054098961345],
+ [9918.26136516881,798.8054098961346],
+ [10017.56136516881,633.2054098961347],
+ [9918.26136516881,467.60540989613474],
+ [9918.26136516881,302.0054098961348],
+ [10017.56136516881,302.0054098961348],
+ [10116.861365168812,136.40540989613478],
+ [10116.861365168812,302.0054098961348],
+ [10116.861365168812,467.60540989613474],
+ [10116.861365168812,633.2054098961347],
+ [10216.161365168813,633.2054098961347],
+ [10216.161365168813,798.8054098961346],
+ [10315.461365168814,633.2054098961347],
+ [10315.461365168814,798.8054098961346],
+ [10414.761365168815,798.8054098961346],
+ [10514.061365168816,633.2054098961347],
+ [10514.061365168816,798.8054098961346],
+ [10414.761365168815,964.4054098961345],
+ [10315.461365168814,964.4054098961345],
+ [10216.161365168813,964.4054098961345],
+ [10116.861365168812,798.8054098961346],
+ [10017.56136516881,798.8054098961346],
+ [10116.861365168812,964.4054098961345],
+ [10216.161365168813,1130.0054098961346],
+ [10116.861365168812,1130.0054098961346],
+ [10216.161365168813,1295.6054098961347],
+ [10216.161365168813,1461.2054098961348],
+ [10315.461365168814,1626.805409896135],
+ [10315.461365168814,1792.405409896135],
+ [10216.161365168813,1958.0054098961352],
+ [10216.161365168813,1792.405409896135],
+ [10116.861365168812,1792.405409896135],
+ [10017.56136516881,1958.0054098961352],
+ [9918.26136516881,2123.6054098961354],
+ [9918.26136516881,1958.0054098961352],
+ [10017.56136516881,2123.6054098961354],
+ [10116.861365168812,2123.6054098961354],
+ [10017.56136516881,2289.2054098961353],
+ [10017.56136516881,2454.805409896135],
+ [10116.861365168812,2289.2054098961353],
+ [10216.161365168813,2454.805409896135],
+ [10315.461365168814,2620.405409896135],
+ [10315.461365168814,2454.805409896135],
+ [10315.461365168814,2289.2054098961353],
+ [10414.761365168815,2454.805409896135],
+ [10514.061365168816,2620.405409896135],
+ [10613.361365168817,2786.005409896135],
+ [10514.061365168816,2786.005409896135],
+ [10613.361365168817,2620.405409896135],
+ [10514.061365168816,2454.805409896135],
+ [10514.061365168816,2289.2054098961353],
+ [10613.361365168817,2289.2054098961353],
+ [10712.661365168819,2289.2054098961353],
+ [10811.96136516882,2454.805409896135],
+ [10911.26136516882,2289.2054098961353],
+ [10811.96136516882,2289.2054098961353],
+ [10712.661365168819,2454.805409896135],
+ [10712.661365168819,2620.405409896135],
+ [10811.96136516882,2786.005409896135],
+ [10911.26136516882,2620.405409896135],
+ [10911.26136516882,2786.005409896135],
+ [11010.561365168822,2620.405409896135],
+ [10911.26136516882,2454.805409896135],
+ [10811.96136516882,2620.405409896135],
+ [10712.661365168819,2786.005409896135],
+ [10811.96136516882,2951.605409896135],
+ [10911.26136516882,2951.605409896135],
+ [10811.96136516882,3117.205409896135],
+ [10712.661365168819,2951.605409896135],
+ [10613.361365168817,2951.605409896135],
+ [10514.061365168816,2951.605409896135],
+ [10414.761365168815,3117.205409896135],
+ [10414.761365168815,2951.605409896135],
+ [10315.461365168814,2786.005409896135],
+ [10216.161365168813,2620.405409896135],
+ [10216.161365168813,2786.005409896135],
+ [10315.461365168814,2951.605409896135],
+ [10315.461365168814,3117.205409896135],
+ [10216.161365168813,3117.205409896135],
+ [10116.861365168812,3117.205409896135],
+ [10017.56136516881,3282.8054098961347],
+ [9918.26136516881,3448.4054098961346],
+ [9818.961365168809,3448.4054098961346],
+ [9818.961365168809,3614.0054098961346],
+ [9719.661365168808,3448.4054098961346],
+ [9818.961365168809,3282.8054098961347],
+ [9719.661365168808,3117.205409896135],
+ [9620.361365168807,2951.605409896135],
+ [9521.061365168805,3117.205409896135],
+ [9521.061365168805,3282.8054098961347],
+ [9421.761365168804,3117.205409896135],
+ [9421.761365168804,3282.8054098961347],
+ [9322.461365168803,3117.205409896135],
+ [9421.761365168804,2951.605409896135],
+ [9322.461365168803,2951.605409896135],
+ [9223.161365168802,2786.005409896135],
+ [9322.461365168803,2620.405409896135],
+ [9421.761365168804,2454.805409896135],
+ [9521.061365168805,2289.2054098961353],
+ [9421.761365168804,2123.6054098961354],
+ [9421.761365168804,1958.0054098961352],
+ [9421.761365168804,1792.405409896135],
+ [9521.061365168805,1626.805409896135],
+ [9421.761365168804,1626.805409896135],
+ [9322.461365168803,1792.405409896135],
+ [9322.461365168803,1626.805409896135],
+ [9322.461365168803,1461.2054098961348],
+ [9421.761365168804,1461.2054098961348],
+ [9521.061365168805,1295.6054098961347],
+ [9421.761365168804,1130.0054098961346],
+ [9322.461365168803,964.4054098961345],
+ [9223.161365168802,964.4054098961345],
+ [9223.161365168802,798.8054098961346],
+ [9322.461365168803,633.2054098961347],
+ [9421.761365168804,798.8054098961346],
+ [9421.761365168804,633.2054098961347],
+ [9521.061365168805,633.2054098961347],
+ [9421.761365168804,467.60540989613474],
+ [9421.761365168804,302.0054098961348],
+ [9322.461365168803,136.40540989613478],
+ [9223.161365168802,302.0054098961348],
+ [9123.861365168801,302.0054098961348],
+ [9024.5613651688,136.40540989613478],
+ [9123.861365168801,136.40540989613478],
+ [9223.161365168802,136.40540989613478],
+ [9322.461365168803,302.0054098961348],
+ [9421.761365168804,136.40540989613478],
+ [9521.061365168805,136.40540989613478],
+ [9620.361365168807,136.40540989613478],
+ [9620.361365168807,302.0054098961348],
+ [9521.061365168805,302.0054098961348],
+ [9521.061365168805,467.60540989613474],
+ [9620.361365168807,467.60540989613474],
+ [9719.661365168808,302.0054098961348],
+ [9719.661365168808,136.40540989613478],
+ [9818.961365168809,136.40540989613478],
+ [9918.26136516881,136.40540989613478],
+ [10017.56136516881,136.40540989613478],
+ [366.07287160549004,5394.185440937868],
+ [465.37287160549005,5394.185440937868],
+ [465.37287160549005,5559.785440937868],
+ [366.0728716054901,5559.785440937868],
+ [366.0728716054901,5725.385440937867],
+ [266.77287160549014,5725.385440937867],
+ [167.47287160549016,5559.785440937868],
+ [266.77287160549014,5559.785440937868],
+ [266.77287160549014,5394.185440937868],
+ [266.77287160549014,5228.585440937869],
+ [167.47287160549016,5394.185440937868],
+ [68.17287160549016,5228.585440937869],
+ [167.47287160549013,5062.9854409378695],
+ [68.17287160549013,4897.38544093787],
+ [167.47287160549013,4731.785440937871],
+ [266.77287160549014,4731.785440937871],
+ [167.47287160549016,4566.185440937871],
+ [68.17287160549016,4566.185440937871],
+ [68.17287160549016,4731.785440937871],
+ [167.47287160549013,4897.38544093787],
+ [68.17287160549013,5062.9854409378695],
+ [167.47287160549013,5228.585440937869],
+ [266.77287160549014,5062.9854409378695],
+ [366.0728716054901,4897.38544093787],
+ [266.77287160549014,4897.38544093787],
+ [366.0728716054901,4731.785440937871],
+ [465.37287160549005,4897.38544093787],
+ [366.0728716054901,5062.9854409378695],
+ [465.37287160549005,5062.9854409378695],
+ [366.0728716054901,5228.585440937869],
+ [465.37287160549005,5228.585440937869],
+ [564.6728716054901,5394.185440937868],
+ [663.9728716054901,5228.585440937869],
+ [564.6728716054901,5062.9854409378695],
+ [663.9728716054901,4897.38544093787],
+ [763.2728716054902,4731.785440937871],
+ [862.5728716054903,4566.185440937871],
+ [961.8728716054903,4731.785440937871],
+ [862.5728716054903,4731.785440937871],
+ [961.8728716054903,4566.185440937871],
+ [862.5728716054903,4400.585440937872],
+ [961.8728716054903,4234.985440937872],
+ [1061.1728716054904,4400.585440937872],
+ [1160.4728716054904,4234.985440937872],
+ [1160.4728716054904,4400.585440937872],
+ [1259.7728716054903,4234.985440937872],
+ [1359.0728716054903,4069.3854409378723],
+ [1458.3728716054902,4069.3854409378723],
+ [1557.6728716054902,4234.985440937872],
+ [1656.9728716054901,4400.585440937872],
+ [1557.6728716054902,4400.585440937872],
+ [1458.3728716054902,4400.585440937872],
+ [1359.0728716054903,4566.185440937871],
+ [1359.0728716054903,4731.785440937871],
+ [1259.7728716054903,4731.785440937871],
+ [1359.0728716054903,4897.38544093787],
+ [1458.3728716054902,4731.785440937871],
+ [1458.3728716054902,4897.38544093787],
+ [1359.0728716054903,5062.9854409378695],
+ [1259.7728716054903,5228.585440937869],
+ [1259.7728716054903,5062.9854409378695],
+ [1259.7728716054903,4897.38544093787],
+ [1160.4728716054904,5062.9854409378695],
+ [1160.4728716054904,5228.585440937869],
+ [1061.1728716054904,5228.585440937869],
+ [1061.1728716054904,5062.9854409378695],
+ [961.8728716054903,5228.585440937869],
+ [862.5728716054903,5062.9854409378695],
+ [961.8728716054903,5062.9854409378695],
+ [961.8728716054903,4897.38544093787],
+ [1061.1728716054904,4897.38544093787],
+ [1160.4728716054904,4731.785440937871],
+ [1259.7728716054903,4566.185440937871],
+ [1359.0728716054903,4400.585440937872],
+ [1458.3728716054902,4566.185440937871],
+ [1557.6728716054902,4566.185440937871],
+ [1656.9728716054901,4731.785440937871],
+ [1557.6728716054902,4897.38544093787],
+ [1458.3728716054902,5062.9854409378695],
+ [1557.6728716054902,5228.585440937869],
+ [1656.9728716054901,5062.9854409378695],
+ [1756.27287160549,5062.9854409378695],
+ [1756.27287160549,4897.38544093787],
+ [1855.57287160549,5062.9854409378695],
+ [1954.87287160549,4897.38544093787],
+ [2054.17287160549,5062.9854409378695],
+ [1954.87287160549,5062.9854409378695],
+ [2054.17287160549,5228.585440937869],
+ [2153.4728716054897,5228.585440937869],
+ [2252.7728716054894,5062.9854409378695],
+ [2352.072871605489,5228.585440937869],
+ [2451.372871605489,5394.185440937868],
+ [2352.072871605489,5394.185440937868],
+ [2252.7728716054894,5228.585440937869],
+ [2153.4728716054897,5062.9854409378695],
+ [2153.4728716054897,4897.38544093787],
+ [2252.7728716054894,4897.38544093787],
+ [2352.072871605489,4731.785440937871],
+ [2252.7728716054894,4731.785440937871],
+ [2153.4728716054897,4731.785440937871],
+ [2054.17287160549,4566.185440937871],
+ [1954.87287160549,4731.785440937871],
+ [1855.57287160549,4897.38544093787],
+ [1756.27287160549,4731.785440937871],
+ [1855.57287160549,4731.785440937871],
+ [1855.57287160549,4566.185440937871],
+ [1756.27287160549,4566.185440937871],
+ [1656.9728716054901,4566.185440937871],
+ [1557.6728716054902,4731.785440937871],
+ [1656.9728716054901,4897.38544093787],
+ [1557.6728716054902,5062.9854409378695],
+ [1458.3728716054902,5228.585440937869],
+ [1359.0728716054903,5228.585440937869],
+ [1259.7728716054903,5394.185440937868],
+ [1259.7728716054903,5559.785440937868],
+ [1160.4728716054904,5559.785440937868],
+ [1061.1728716054904,5559.785440937868],
+ [1160.4728716054904,5725.385440937867],
+ [1259.7728716054903,5725.385440937867],
+ [1359.0728716054903,5559.785440937868],
+ [1458.3728716054902,5725.385440937867],
+ [1458.3728716054902,5559.785440937868],
+ [1359.0728716054903,5725.385440937867],
+ [1259.7728716054903,5890.985440937867],
+ [1359.0728716054903,5890.985440937867],
+ [1259.7728716054903,6056.585440937866],
+ [1359.0728716054903,6222.185440937866],
+ [1458.3728716054902,6222.185440937866],
+ [1458.3728716054902,6387.785440937865],
+ [1557.6728716054902,6222.185440937866],
+ [1557.6728716054902,6387.785440937865],
+ [1656.9728716054901,6222.185440937866],
+ [1756.27287160549,6056.585440937866],
+ [1855.57287160549,5890.985440937867],
+ [1756.27287160549,5890.985440937867],
+ [1656.9728716054901,6056.585440937866],
+ [1557.6728716054902,5890.985440937867],
+ [1458.3728716054902,5890.985440937867],
+ [1359.0728716054903,6056.585440937866],
+ [1259.7728716054903,6222.185440937866],
+ [1160.4728716054904,6056.585440937866],
+ [1061.1728716054904,5890.985440937867],
+ [1061.1728716054904,6056.585440937866],
+ [1160.4728716054904,6222.185440937866],
+ [1061.1728716054904,6222.185440937866],
+ [961.8728716054903,6222.185440937866],
+ [961.8728716054903,6056.585440937866],
+ [961.8728716054903,5890.985440937867],
+ [961.8728716054903,5725.385440937867],
+ [862.5728716054903,5559.785440937868],
+ [763.2728716054902,5725.385440937867],
+ [862.5728716054903,5725.385440937867],
+ [763.2728716054902,5890.985440937867],
+ [663.9728716054901,5725.385440937867],
+ [763.2728716054902,5559.785440937868],
+ [763.2728716054902,5394.185440937868],
+ [862.5728716054903,5228.585440937869],
+ [961.8728716054903,5394.185440937868],
+ [1061.1728716054904,5394.185440937868],
+ [961.8728716054903,5559.785440937868],
+ [862.5728716054903,5394.185440937868],
+ [763.2728716054902,5228.585440937869],
+ [663.9728716054901,5062.9854409378695],
+ [763.2728716054902,5062.9854409378695],
+ [763.2728716054902,4897.38544093787],
+ [663.9728716054901,4731.785440937871],
+ [564.6728716054901,4731.785440937871],
+ [465.37287160549005,4566.185440937871],
+ [366.0728716054901,4566.185440937871],
+ [465.37287160549005,4731.785440937871],
+ [564.6728716054901,4566.185440937871],
+ [465.37287160549005,4400.585440937872],
+ [366.0728716054901,4400.585440937872],
+ [266.77287160549014,4234.985440937872],
+ [167.47287160549016,4234.985440937872],
+ [266.77287160549014,4400.585440937872],
+ [266.77287160549014,4566.185440937871],
+ [167.47287160549016,4400.585440937872],
+ [68.17287160549016,4234.985440937872],
+ [167.47287160549013,4069.3854409378723],
+ [68.17287160549013,3903.7854409378724],
+ [68.17287160549013,4069.3854409378723],
+ [167.47287160549013,3903.7854409378724],
+ [266.77287160549014,3903.7854409378724],
+ [366.0728716054901,3738.1854409378725],
+ [266.77287160549014,3738.1854409378725],
+ [266.77287160549014,3572.5854409378726],
+ [167.47287160549016,3406.9854409378727],
+ [167.47287160549016,3241.3854409378728],
+ [266.77287160549014,3241.3854409378728],
+ [266.77287160549014,3406.9854409378727],
+ [366.0728716054901,3572.5854409378726],
+ [465.37287160549005,3738.1854409378725],
+ [465.37287160549005,3903.7854409378724],
+ [366.0728716054901,4069.3854409378723],
+ [366.0728716054901,4234.985440937872],
+ [465.37287160549005,4234.985440937872],
+ [564.6728716054901,4069.3854409378723],
+ [465.37287160549005,4069.3854409378723],
+ [564.6728716054901,4234.985440937872],
+ [663.9728716054901,4069.3854409378723],
+ [663.9728716054901,4234.985440937872],
+ [663.9728716054901,4400.585440937872],
+ [763.2728716054902,4566.185440937871],
+ [763.2728716054902,4400.585440937872],
+ [663.9728716054901,4566.185440937871],
+ [564.6728716054901,4400.585440937872],
+ [19431.915041401327,3495.506142643713],
+ [19332.61504140133,3661.1061426437127],
+ [19431.915041401327,3661.1061426437127],
+ [19531.215041401327,3661.1061426437127],
+ [19630.515041401326,3495.506142643713],
+ [19630.515041401326,3661.1061426437127],
+ [19729.815041401325,3826.7061426437126],
+ [19630.515041401326,3826.7061426437126],
+ [19729.815041401325,3992.3061426437125],
+ [19630.515041401326,3992.3061426437125],
+ [19630.515041401326,4157.906142643712],
+ [19630.515041401326,4323.506142643711],
+ [19531.215041401327,4157.906142643712],
+ [19431.915041401327,4323.506142643711],
+ [19531.215041401327,4489.106142643711],
+ [19431.915041401327,4654.70614264371],
+ [19332.61504140133,4654.70614264371],
+ [19332.61504140133,4820.30614264371],
+ [19332.61504140133,4985.906142643709],
+ [19233.31504140133,4985.906142643709],
+ [19134.01504140133,5151.506142643709],
+ [19034.71504140133,5151.506142643709],
+ [19134.01504140133,5317.106142643708],
+ [19034.71504140133,5317.106142643708],
+ [19034.71504140133,5482.706142643708],
+ [18935.41504140133,5648.306142643707],
+ [18836.115041401332,5813.9061426437065],
+ [18836.115041401332,5979.506142643706],
+ [18935.41504140133,5979.506142643706],
+ [19034.71504140133,6145.106142643705],
+ [19034.71504140133,5979.506142643706],
+ [19034.71504140133,5813.9061426437065],
+ [19134.01504140133,5648.306142643707],
+ [19233.31504140133,5648.306142643707],
+ [19134.01504140133,5813.9061426437065],
+ [19134.01504140133,5979.506142643706],
+ [19233.31504140133,5813.9061426437065],
+ [19233.31504140133,5979.506142643706],
+ [19332.61504140133,6145.106142643705],
+ [19332.61504140133,6310.706142643705],
+ [19233.31504140133,6310.706142643705],
+ [19233.31504140133,6476.306142643704],
+ [19332.61504140133,6476.306142643704],
+ [19431.915041401327,6641.906142643704],
+ [19332.61504140133,6807.506142643703],
+ [19332.61504140133,6641.906142643704],
+ [19431.915041401327,6476.306142643704],
+ [19431.915041401327,6310.706142643705],
+ [19531.215041401327,6145.106142643705],
+ [19431.915041401327,5979.506142643706],
+ [19431.915041401327,6145.106142643705],
+ [19531.215041401327,5979.506142643706],
+ [19630.515041401326,5813.9061426437065],
+ [19630.515041401326,5979.506142643706],
+ [19729.815041401325,5813.9061426437065],
+ [19829.115041401325,5979.506142643706],
+ [19729.815041401325,5979.506142643706],
+ [19729.815041401325,6145.106142643705],
+ [19729.815041401325,6310.706142643705],
+ [19630.515041401326,6476.306142643704],
+ [19729.815041401325,6476.306142643704],
+ [19630.515041401326,6310.706142643705],
+ [19531.215041401327,6310.706142643705],
+ [19531.215041401327,6476.306142643704],
+ [19630.515041401326,6641.906142643704],
+ [19729.815041401325,6807.506142643703],
+ [19829.115041401325,6973.106142643703],
+ [19928.415041401324,6973.106142643703],
+ [19928.415041401324,7138.706142643702],
+ [20027.715041401323,7138.706142643702],
+ [20027.715041401323,7304.306142643702],
+ [19928.415041401324,7304.306142643702],
+ [19829.115041401325,7304.306142643702],
+ [19829.115041401325,7469.906142643701],
+ [19928.415041401324,7469.906142643701],
+ [19928.415041401324,7635.5061426437005],
+ [19928.415041401324,7801.1061426437],
+ [20027.715041401323,7635.5061426437005],
+ [20027.715041401323,7801.1061426437],
+ [20127.015041401322,7801.1061426437],
+ [20226.31504140132,7801.1061426437],
+ [20325.61504140132,7801.1061426437],
+ [20226.31504140132,7635.5061426437005],
+ [20226.31504140132,7469.906142643701],
+ [20226.31504140132,7304.306142643702],
+ [20127.015041401322,7304.306142643702],
+ [20027.715041401323,7469.906142643701],
+ [20127.015041401322,7469.906142643701],
+ [20127.015041401322,7635.5061426437005],
+ [2748.790306732237,2362.9553147492866],
+ [2848.0903067322365,2528.5553147492865],
+ [2748.790306732237,2694.1553147492864],
+ [2649.490306732237,2859.7553147492863],
+ [2748.790306732237,3025.355314749286],
+ [2848.0903067322365,2859.7553147492863],
+ [2848.0903067322365,2694.1553147492864],
+ [2947.3903067322362,2694.1553147492864],
+ [3046.690306732236,2859.7553147492863],
+ [3145.9903067322357,2694.1553147492864],
+ [3145.9903067322357,2528.5553147492865],
+ [3046.690306732236,2694.1553147492864],
+ [3145.9903067322357,2859.7553147492863],
+ [3046.690306732236,3025.355314749286],
+ [3145.9903067322357,3025.355314749286],
+ [3245.2903067322354,3190.955314749286],
+ [3245.2903067322354,3356.555314749286],
+ [3344.590306732235,3522.155314749286],
+ [3443.890306732235,3356.555314749286],
+ [3543.1903067322346,3356.555314749286],
+ [3642.4903067322343,3190.955314749286],
+ [3741.790306732234,3025.355314749286],
+ [3741.790306732234,2859.7553147492863],
+ [3841.090306732234,3025.355314749286],
+ [3841.090306732234,3190.955314749286],
+ [3741.790306732234,3190.955314749286],
+ [3642.4903067322343,3025.355314749286],
+ [3543.1903067322346,3025.355314749286],
+ [3543.1903067322346,2859.7553147492863],
+ [3443.890306732235,3025.355314749286],
+ [3443.890306732235,3190.955314749286],
+ [3543.1903067322346,3190.955314749286],
+ [3642.4903067322343,3356.555314749286],
+ [3543.1903067322346,3522.155314749286],
+ [3443.890306732235,3687.755314749286],
+ [3443.890306732235,3853.3553147492858],
+ [3344.590306732235,3687.755314749286],
+ [3245.2903067322354,3853.3553147492858],
+ [3245.2903067322354,3687.755314749286],
+ [3145.9903067322357,3687.755314749286],
+ [3046.690306732236,3853.3553147492858],
+ [3145.9903067322357,4018.9553147492857],
+ [3145.9903067322357,3853.3553147492858],
+ [3046.690306732236,3687.755314749286],
+ [3145.9903067322357,3522.155314749286],
+ [3145.9903067322357,3356.555314749286],
+ [3145.9903067322357,3190.955314749286],
+ [3046.690306732236,3190.955314749286],
+ [3046.690306732236,3356.555314749286],
+ [2947.3903067322362,3356.555314749286],
+ [2848.0903067322365,3190.955314749286],
+ [2947.3903067322362,3025.355314749286],
+ [2848.0903067322365,3025.355314749286],
+ [2748.790306732237,2859.7553147492863],
+ [2649.490306732237,2694.1553147492864],
+ [2748.790306732237,2528.5553147492865],
+ [2848.0903067322365,2362.9553147492866],
+ [2748.790306732237,2197.3553147492867],
+ [2649.490306732237,2362.9553147492866],
+ [2649.490306732237,2197.3553147492867],
+ [2550.1903067322373,2362.9553147492866],
+ [2450.8903067322376,2362.9553147492866],
+ [2351.590306732238,2528.5553147492865],
+ [2252.290306732238,2528.5553147492865],
+ [2351.590306732238,2362.9553147492866],
+ [2252.290306732238,2197.3553147492867],
+ [2351.590306732238,2197.3553147492867],
+ [2351.590306732238,2031.7553147492865],
+ [2351.590306732238,1866.1553147492864],
+ [2252.290306732238,1866.1553147492864],
+ [2351.590306732238,1700.5553147492863],
+ [2450.8903067322376,1534.9553147492861],
+ [2351.590306732238,1369.355314749286],
+ [2252.290306732238,1203.7553147492858],
+ [2252.290306732238,1369.355314749286],
+ [2252.290306732238,1534.9553147492861],
+ [2152.9903067322384,1369.355314749286],
+ [2053.6903067322387,1369.355314749286],
+ [1954.3903067322387,1203.7553147492858],
+ [1855.0903067322388,1203.7553147492858],
+ [1755.7903067322388,1038.1553147492857],
+ [1656.4903067322389,1038.1553147492857],
+ [1557.190306732239,872.5553147492857],
+ [1457.890306732239,1038.1553147492857],
+ [1457.890306732239,872.5553147492857],
+ [1457.890306732239,706.9553147492858],
+ [1557.190306732239,706.9553147492858],
+ [1656.4903067322389,872.5553147492857],
+ [1656.4903067322389,706.9553147492858],
+ [1755.7903067322388,706.9553147492858],
+ [1656.4903067322389,541.3553147492859],
+ [1557.190306732239,375.7553147492859],
+ [1656.4903067322389,210.1553147492859],
+ [1755.7903067322388,44.55531474928592],
+ [1656.4903067322389,44.55531474928592],
+ [1557.190306732239,210.1553147492859],
+ [1457.890306732239,210.1553147492859],
+ [1457.890306732239,44.55531474928592],
+ [1358.590306732239,210.1553147492859],
+ [1358.590306732239,375.75531474928584],
+ [1259.290306732239,210.15531474928585],
+ [1259.290306732239,375.75531474928584],
+ [1259.290306732239,541.3553147492859],
+ [1358.590306732239,706.9553147492858],
+ [1358.590306732239,872.5553147492857],
+ [1259.290306732239,706.9553147492858],
+ [1259.290306732239,872.5553147492857],
+ [1259.290306732239,1038.1553147492857],
+ [1358.590306732239,1203.7553147492858],
+ [1358.590306732239,1038.1553147492857],
+ [1457.890306732239,1203.7553147492858],
+ [1557.190306732239,1369.355314749286],
+ [1656.4903067322389,1203.7553147492858],
+ [1557.190306732239,1203.7553147492858],
+ [1557.190306732239,1038.1553147492857],
+ [17254.572515546668,1460.5807801244923],
+ [17353.872515546667,1626.1807801244925],
+ [17453.172515546667,1791.7807801244926],
+ [17552.472515546666,1791.7807801244926],
+ [17453.172515546667,1626.1807801244925],
+ [17353.872515546667,1791.7807801244926],
+ [17453.172515546667,1957.3807801244927],
+ [17353.872515546667,2122.980780124493],
+ [17453.172515546667,2288.580780124493],
+ [17353.872515546667,2454.1807801244927],
+ [17453.172515546667,2619.7807801244926],
+ [17552.472515546666,2619.7807801244926],
+ [17453.172515546667,2785.3807801244925],
+ [17353.872515546667,2619.7807801244926],
+ [17254.572515546668,2454.1807801244927],
+ [17254.572515546668,2288.580780124493],
+ [17353.872515546667,2288.580780124493],
+ [17453.172515546667,2122.980780124493],
+ [17552.472515546666,2288.580780124493],
+ [17552.472515546666,2454.1807801244927],
+ [17453.172515546667,2454.1807801244927],
+ [4447.67624466283,4761.1416826913],
+ [4546.97624466283,4595.541682691301],
+ [4546.97624466283,4429.941682691301],
+ [4447.67624466283,4429.941682691301],
+ [4447.67624466283,4595.541682691301],
+ [4348.37624466283,4595.541682691301],
+ [4249.07624466283,4595.541682691301],
+ [4348.37624466283,4761.1416826913],
+ [4249.07624466283,4761.1416826913],
+ [4348.37624466283,4926.7416826912995],
+ [4348.37624466283,5092.341682691299],
+ [4447.67624466283,5257.941682691298],
+ [4546.97624466283,5257.941682691298],
+ [4646.27624466283,5092.341682691299],
+ [4546.97624466283,5092.341682691299],
+ [4646.27624466283,4926.7416826912995],
+ [4646.27624466283,4761.1416826913],
+ [4546.97624466283,4761.1416826913],
+ [4646.27624466283,4595.541682691301],
+ [4745.5762446628305,4595.541682691301],
+ [4646.27624466283,4429.941682691301],
+ [4745.5762446628305,4429.941682691301],
+ [4844.876244662831,4595.541682691301],
+ [4745.5762446628305,4761.1416826913],
+ [4745.5762446628305,4926.7416826912995],
+ [4844.876244662831,4761.1416826913],
+ [4944.176244662831,4761.1416826913],
+ [5043.476244662831,4926.7416826912995],
+ [5043.476244662831,4761.1416826913],
+ [5142.776244662831,4926.7416826912995],
+ [5142.776244662831,4761.1416826913],
+ [5242.076244662831,4595.541682691301],
+ [5142.776244662831,4595.541682691301],
+ [5242.076244662831,4429.941682691301],
+ [5242.076244662831,4264.341682691302],
+ [5142.776244662831,4429.941682691301],
+ [5043.476244662831,4595.541682691301],
+ [5043.476244662831,4429.941682691301],
+ [5043.476244662831,4264.341682691302],
+ [5142.776244662831,4098.741682691302],
+ [5043.476244662831,4098.741682691302],
+ [4944.176244662831,3933.1416826913023],
+ [4944.176244662831,4098.741682691302],
+ [4944.176244662831,4264.341682691302],
+ [4844.876244662831,4098.741682691302],
+ [4745.5762446628305,4264.341682691302],
+ [4646.27624466283,4098.741682691302],
+ [4546.97624466283,3933.1416826913023],
+ [4447.67624466283,4098.741682691302],
+ [4546.97624466283,4264.341682691302],
+ [4447.67624466283,4264.341682691302],
+ [4546.97624466283,4098.741682691302],
+ [4646.27624466283,3933.1416826913023],
+ [4546.97624466283,3767.5416826913024],
+ [4447.67624466283,3601.9416826913025],
+ [4447.67624466283,3767.5416826913024],
+ [4348.37624466283,3767.5416826913024],
+ [4348.37624466283,3933.1416826913023],
+ [4249.07624466283,3767.5416826913024],
+ [4249.07624466283,3933.1416826913023],
+ [4149.776244662829,3933.1416826913023],
+ [4050.4762446628297,4098.741682691302],
+ [4050.4762446628297,3933.1416826913023],
+ [3951.17624466283,3933.1416826913023],
+ [3951.17624466283,4098.741682691302],
+ [3851.8762446628302,4264.341682691302],
+ [3851.8762446628302,4098.741682691302],
+ [3752.5762446628305,4098.741682691302],
+ [3653.276244662831,4264.341682691302],
+ [3553.976244662831,4429.941682691301],
+ [3553.976244662831,4595.541682691301],
+ [3454.6762446628313,4429.941682691301],
+ [3553.976244662831,4264.341682691302],
+ [3653.276244662831,4429.941682691301],
+ [3752.5762446628305,4264.341682691302],
+ [3752.5762446628305,4429.941682691301],
+ [3851.8762446628302,4595.541682691301],
+ [3851.8762446628302,4429.941682691301],
+ [3951.17624466283,4429.941682691301],
+ [4050.4762446628297,4264.341682691302],
+ [4149.776244662829,4098.741682691302],
+ [4249.07624466283,4264.341682691302],
+ [4348.37624466283,4098.741682691302],
+ [4447.67624466283,3933.1416826913023],
+ [9574.088902135607,7352.26293905581],
+ [9474.788902135606,7352.26293905581],
+ [9375.488902135605,7186.662939055811],
+ [9474.788902135606,7021.0629390558115],
+ [9574.088902135607,7021.0629390558115],
+ [9474.788902135606,7186.662939055811],
+ [9574.088902135607,7186.662939055811],
+ [9673.388902135608,7021.0629390558115],
+ [9673.388902135608,6855.462939055812],
+ [9772.68890213561,6689.862939055813],
+ [9673.388902135608,6689.862939055813],
+ [9772.68890213561,6524.262939055813],
+ [9871.98890213561,6358.662939055814],
+ [9971.288902135611,6524.262939055813],
+ [10070.588902135612,6358.662939055814],
+ [10070.588902135612,6193.062939055814],
+ [9971.288902135611,6027.462939055815],
+ [9971.288902135611,5861.862939055815],
+ [9871.98890213561,5861.862939055815],
+ [9871.98890213561,5696.262939055816],
+ [9971.288902135611,5530.662939055816],
+ [10070.588902135612,5530.662939055816],
+ [10070.588902135612,5696.262939055816],
+ [10169.888902135614,5861.862939055815],
+ [10169.888902135614,5696.262939055816],
+ [10070.588902135612,5861.862939055815],
+ [10169.888902135614,6027.462939055815],
+ [10169.888902135614,6193.062939055814],
+ [10269.188902135615,6027.462939055815],
+ [10269.188902135615,5861.862939055815],
+ [10368.488902135616,6027.462939055815],
+ [10269.188902135615,6193.062939055814],
+ [10269.188902135615,6358.662939055814],
+ [10169.888902135614,6358.662939055814],
+ [10070.588902135612,6524.262939055813],
+ [10070.588902135612,6689.862939055813],
+ [9971.288902135611,6855.462939055812],
+ [9971.288902135611,7021.0629390558115],
+ [10070.588902135612,7186.662939055811],
+ [10169.888902135614,7186.662939055811],
+ [10269.188902135615,7186.662939055811],
+ [10169.888902135614,7352.26293905581],
+ [10070.588902135612,7352.26293905581],
+ [10169.888902135614,7517.86293905581],
+ [10169.888902135614,7683.462939055809],
+ [10269.188902135615,7517.86293905581],
+ [10368.488902135616,7683.462939055809],
+ [10467.788902135617,7683.462939055809],
+ [10368.488902135616,7517.86293905581],
+ [10269.188902135615,7352.26293905581],
+ [10368.488902135616,7352.26293905581],
+ [10368.488902135616,7186.662939055811],
+ [10368.488902135616,7021.0629390558115],
+ [10368.488902135616,6855.462939055812],
+ [10269.188902135615,6855.462939055812],
+ [10169.888902135614,6855.462939055812],
+ [10169.888902135614,7021.0629390558115],
+ [10070.588902135612,7021.0629390558115],
+ [10070.588902135612,6855.462939055812],
+ [10169.888902135614,6689.862939055813],
+ [10269.188902135615,6689.862939055813],
+ [10169.888902135614,6524.262939055813],
+ [10269.188902135615,6524.262939055813],
+ [10368.488902135616,6524.262939055813],
+ [10368.488902135616,6358.662939055814],
+ [10467.788902135617,6358.662939055814],
+ [10467.788902135617,6193.062939055814],
+ [10567.088902135618,6358.662939055814],
+ [10567.088902135618,6193.062939055814],
+ [10666.388902135619,6193.062939055814],
+ [10666.388902135619,6358.662939055814],
+ [10567.088902135618,6524.262939055813],
+ [10467.788902135617,6524.262939055813],
+ [10567.088902135618,6689.862939055813],
+ [10467.788902135617,6855.462939055812],
+ [10567.088902135618,7021.0629390558115],
+ [10467.788902135617,7021.0629390558115],
+ [10567.088902135618,6855.462939055812],
+ [10467.788902135617,6689.862939055813],
+ [10368.488902135616,6689.862939055813],
+ [1073.6944354374714,1154.3681204032646],
+ [974.3944354374713,1319.9681204032647],
+ [875.0944354374712,1319.9681204032647],
+ [775.7944354374712,1154.3681204032646],
+ [775.7944354374712,988.7681204032646],
+ [875.0944354374712,823.1681204032647],
+ [875.0944354374712,657.5681204032647],
+ [775.7944354374712,823.1681204032647],
+ [676.4944354374711,657.5681204032647],
+ [676.4944354374711,491.9681204032648],
+ [775.7944354374712,657.5681204032647],
+ [676.4944354374711,823.1681204032647],
+ [676.4944354374711,988.7681204032646],
+ [577.194435437471,823.1681204032647],
+ [577.194435437471,988.7681204032646],
+ [577.194435437471,1154.3681204032646],
+ [676.4944354374711,1319.9681204032647],
+ [577.194435437471,1319.9681204032647],
+ [477.89443543747103,1319.9681204032647],
+ [577.194435437471,1485.5681204032649],
+ [477.89443543747103,1651.168120403265],
+ [577.194435437471,1816.7681204032651],
+ [477.89443543747103,1816.7681204032651],
+ [378.5944354374711,1982.3681204032653],
+ [378.5944354374711,2147.9681204032654],
+ [279.2944354374711,2313.5681204032653],
+ [179.99443543747114,2147.9681204032654],
+ [80.69443543747114,2313.5681204032653],
+ [80.69443543747114,2479.168120403265],
+ [179.9944354374711,2644.768120403265],
+ [179.9944354374711,2479.168120403265],
+ [179.9944354374711,2313.5681204032653],
+ [80.69443543747111,2147.9681204032654],
+ [80.69443543747111,1982.3681204032653],
+ [179.9944354374711,1982.3681204032653],
+ [179.9944354374711,1816.7681204032651],
+ [80.69443543747111,1816.7681204032651],
+ [179.9944354374711,1651.168120403265],
+ [80.69443543747111,1485.5681204032649],
+ [80.69443543747111,1319.9681204032647],
+ [179.9944354374711,1154.3681204032646],
+ [80.69443543747111,1154.3681204032646],
+ [179.9944354374711,988.7681204032646],
+ [279.2944354374711,823.1681204032647],
+ [378.5944354374711,657.5681204032647],
+ [378.5944354374711,823.1681204032647],
+ [477.89443543747103,823.1681204032647],
+ [477.89443543747103,657.5681204032647],
+ [378.5944354374711,491.9681204032648],
+ [477.89443543747103,326.3681204032648],
+ [477.89443543747103,160.76812040326482],
+ [378.5944354374711,160.76812040326482],
+ [279.2944354374711,326.3681204032648],
+ [179.99443543747114,491.9681204032648],
+ [179.99443543747114,326.3681204032648],
+ [279.2944354374711,491.9681204032648],
+ [279.2944354374711,657.5681204032647],
+ [179.99443543747114,823.1681204032647],
+ [279.2944354374711,988.7681204032646],
+ [279.2944354374711,1154.3681204032646],
+ [378.5944354374711,1319.9681204032647],
+ [477.89443543747103,1485.5681204032649],
+ [577.194435437471,1651.168120403265],
+ [676.4944354374711,1651.168120403265],
+ [775.7944354374712,1816.7681204032651],
+ [676.4944354374711,1816.7681204032651],
+ [775.7944354374712,1651.168120403265],
+ [875.0944354374712,1651.168120403265],
+ [974.3944354374713,1651.168120403265],
+ [875.0944354374712,1485.5681204032649],
+ [775.7944354374712,1485.5681204032649],
+ [676.4944354374711,1485.5681204032649],
+ [775.7944354374712,1319.9681204032647],
+ [676.4944354374711,1154.3681204032646],
+ [3138.413562431697,2355.845602060523],
+ [3039.113562431697,2521.445602060523],
+ [3039.113562431697,2355.845602060523],
+ [3039.113562431697,2190.245602060523],
+ [3138.413562431697,2024.645602060523],
+ [3237.7135624316966,1859.045602060523],
+ [3237.7135624316966,2024.645602060523],
+ [3337.0135624316963,1859.045602060523],
+ [3337.0135624316963,1693.4456020605228],
+ [3436.313562431696,1527.8456020605227],
+ [3535.6135624316958,1693.4456020605228],
+ [3535.6135624316958,1859.045602060523],
+ [3634.9135624316955,2024.645602060523],
+ [3734.213562431695,2190.245602060523],
+ [3634.9135624316955,2190.245602060523],
+ [3535.6135624316958,2190.245602060523],
+ [3535.6135624316958,2355.845602060523],
+ [3535.6135624316958,2521.445602060523],
+ [3436.313562431696,2687.045602060523],
+ [3436.313562431696,2852.645602060523],
+ [3535.6135624316958,2687.045602060523],
+ [3634.9135624316955,2521.445602060523],
+ [3634.9135624316955,2355.845602060523],
+ [3734.213562431695,2355.845602060523],
+ [3833.513562431695,2190.245602060523],
+ [3932.8135624316947,2024.645602060523],
+ [3833.513562431695,1859.045602060523],
+ [3833.513562431695,1693.4456020605228],
+ [3734.213562431695,1859.045602060523],
+ [3734.213562431695,1693.4456020605228],
+ [3734.213562431695,1527.8456020605227],
+ [3634.9135624316955,1527.8456020605227],
+ [3634.9135624316955,1693.4456020605228],
+ [3535.6135624316958,1527.8456020605227],
+ [3634.9135624316955,1362.2456020605225],
+ [3535.6135624316958,1362.2456020605225],
+ [3436.313562431696,1196.6456020605224],
+ [3535.6135624316958,1196.6456020605224],
+ [3535.6135624316958,1031.0456020605222],
+ [3436.313562431696,1031.0456020605222],
+ [3535.6135624316958,865.4456020605222],
+ [3436.313562431696,865.4456020605222],
+ [3535.6135624316958,699.8456020605223],
+ [3634.9135624316955,699.8456020605223],
+ [3535.6135624316958,534.2456020605224],
+ [3436.313562431696,368.64560206052244],
+ [3436.313562431696,203.04560206052244],
+ [3337.0135624316963,37.445602060522454],
+ [3436.313562431696,37.445602060522454],
+ [3337.0135624316963,203.04560206052244],
+ [3237.7135624316966,37.445602060522454],
+ [3138.413562431697,37.445602060522454],
+ [3237.7135624316966,203.04560206052244],
+ [3337.0135624316963,368.6456020605224],
+ [3436.313562431696,534.2456020605224],
+ [3337.0135624316963,699.8456020605223],
+ [3237.7135624316966,534.2456020605224],
+ [3337.0135624316963,534.2456020605224],
+ [3436.313562431696,699.8456020605223],
+ [3337.0135624316963,865.4456020605222],
+ [3237.7135624316966,865.4456020605222],
+ [3337.0135624316963,1031.0456020605222],
+ [3237.7135624316966,1196.6456020605224],
+ [3138.413562431697,1362.2456020605225],
+ [3039.113562431697,1527.8456020605227],
+ [3138.413562431697,1527.8456020605227],
+ [3039.113562431697,1693.4456020605228],
+ [2939.8135624316974,1527.8456020605227],
+ [2840.5135624316977,1362.2456020605225],
+ [2840.5135624316977,1527.8456020605227],
+ [2840.5135624316977,1693.4456020605228],
+ [2939.8135624316974,1859.045602060523],
+ [2840.5135624316977,2024.645602060523],
+ [2840.5135624316977,1859.045602060523],
+ [2939.8135624316974,1693.4456020605228],
+ [3039.113562431697,1859.045602060523],
+ [3039.113562431697,2024.645602060523],
+ [2939.8135624316974,2190.245602060523],
+ [2939.8135624316974,2024.645602060523],
+ [16388.412117675925,1839.818884803299],
+ [16289.112117675924,1839.818884803299],
+ [16388.412117675925,1674.2188848032988],
+ [16487.712117675925,1508.6188848032987],
+ [16487.712117675925,1674.2188848032988],
+ [16388.412117675925,1508.6188848032987],
+ [16289.112117675924,1343.0188848032985],
+ [16289.112117675924,1508.6188848032987],
+ [16189.812117675923,1674.2188848032988],
+ [16090.512117675922,1839.818884803299],
+ [16090.512117675922,2005.418884803299],
+ [15991.212117675921,2171.018884803299],
+ [16090.512117675922,2336.618884803299],
+ [16090.512117675922,2502.218884803299],
+ [16090.512117675922,2667.8188848032987],
+ [15991.212117675921,2833.4188848032986],
+ [15991.212117675921,2999.0188848032985],
+ [15891.91211767592,3164.6188848032984],
+ [15891.91211767592,3330.2188848032984],
+ [15991.212117675921,3330.2188848032984],
+ [16090.512117675922,3330.2188848032984],
+ [16189.812117675923,3495.8188848032983],
+ [16289.112117675924,3495.8188848032983],
+ [16189.812117675923,3330.2188848032984],
+ [16189.812117675923,3164.6188848032984],
+ [16289.112117675924,3164.6188848032984],
+ [16388.412117675925,3164.6188848032984],
+ [16388.412117675925,3330.2188848032984],
+ [16487.712117675925,3330.2188848032984],
+ [16587.012117675924,3495.8188848032983],
+ [16587.012117675924,3661.418884803298],
+ [16686.312117675923,3661.418884803298],
+ [16785.612117675922,3661.418884803298],
+ [16884.91211767592,3661.418884803298],
+ [16984.21211767592,3661.418884803298],
+ [16884.91211767592,3827.018884803298],
+ [16884.91211767592,3992.618884803298],
+ [16984.21211767592,3827.018884803298],
+ [17083.51211767592,3661.418884803298],
+ [17182.81211767592,3495.8188848032983],
+ [17182.81211767592,3330.2188848032984],
+ [17282.11211767592,3164.6188848032984],
+ [17282.11211767592,3330.2188848032984],
+ [17182.81211767592,3164.6188848032984],
+ [17083.51211767592,3164.6188848032984],
+ [16984.21211767592,3330.2188848032984],
+ [16984.21211767592,3495.8188848032983],
+ [17083.51211767592,3330.2188848032984],
+ [16984.21211767592,3164.6188848032984],
+ [16984.21211767592,2999.0188848032985],
+ [17083.51211767592,2833.4188848032986],
+ [17083.51211767592,2667.8188848032987],
+ [17182.81211767592,2667.8188848032987],
+ [17182.81211767592,2833.4188848032986],
+ [17083.51211767592,2999.0188848032985],
+ [16984.21211767592,2833.4188848032986],
+ [16884.91211767592,2833.4188848032986],
+ [16884.91211767592,2999.0188848032985],
+ [16785.612117675922,2999.0188848032985],
+ [16884.91211767592,3164.6188848032984],
+ [16785.612117675922,3164.6188848032984],
+ [16686.312117675923,3164.6188848032984],
+ [16587.012117675924,3164.6188848032984],
+ [16587.012117675924,2999.0188848032985],
+ [16487.712117675925,3164.6188848032984],
+ [16587.012117675924,3330.2188848032984],
+ [16686.312117675923,3495.8188848032983],
+ [16686.312117675923,3330.2188848032984],
+ [16785.612117675922,3330.2188848032984],
+ [16884.91211767592,3495.8188848032983],
+ [16785.612117675922,3495.8188848032983],
+ [16884.91211767592,3330.2188848032984],
+ [1272.175991128079,3842.7700224365044],
+ [1371.475991128079,3842.7700224365044],
+ [1272.175991128079,3677.1700224365045],
+ [1172.875991128079,3511.5700224365046],
+ [1272.175991128079,3511.5700224365046],
+ [1172.875991128079,3345.9700224365047],
+ [1073.575991128079,3180.3700224365048],
+ [1073.575991128079,3014.770022436505],
+ [974.275991128079,3014.770022436505],
+ [874.9759911280789,3014.770022436505],
+ [775.6759911280789,2849.170022436505],
+ [775.6759911280789,3014.770022436505],
+ [775.6759911280789,3180.3700224365048],
+ [676.3759911280788,3345.9700224365047],
+ [676.3759911280788,3511.5700224365046],
+ [775.6759911280789,3677.1700224365045],
+ [676.3759911280788,3842.7700224365044],
+ [577.0759911280787,3842.7700224365044],
+ [577.0759911280787,3677.1700224365045],
+ [676.3759911280788,3677.1700224365045],
+ [775.6759911280789,3511.5700224365046],
+ [775.6759911280789,3345.9700224365047],
+ [874.9759911280789,3345.9700224365047],
+ [874.9759911280789,3180.3700224365048],
+ [974.275991128079,3180.3700224365048],
+ [974.275991128079,3345.9700224365047],
+ [1073.575991128079,3511.5700224365046],
+ [1073.575991128079,3677.1700224365045],
+ [1172.875991128079,3677.1700224365045],
+ [1172.875991128079,3842.7700224365044],
+ [1073.575991128079,3842.7700224365044],
+ [1172.875991128079,4008.3700224365043],
+ [1073.575991128079,4008.3700224365043],
+ [974.275991128079,3842.7700224365044],
+ [974.275991128079,4008.3700224365043],
+ [874.9759911280789,4008.3700224365043],
+ [775.6759911280789,4008.3700224365043],
+ [874.9759911280789,3842.7700224365044],
+ [974.275991128079,3677.1700224365045],
+ [974.275991128079,3511.5700224365046],
+ [1073.575991128079,3345.9700224365047],
+ [1172.875991128079,3180.3700224365048],
+ [1272.175991128079,3180.3700224365048],
+ [1272.175991128079,3345.9700224365047],
+ [1371.475991128079,3180.3700224365048],
+ [1470.7759911280789,3345.9700224365047],
+ [1371.475991128079,3345.9700224365047],
+ [1371.475991128079,3511.5700224365046],
+ [1470.7759911280789,3511.5700224365046],
+ [1570.0759911280788,3677.1700224365045],
+ [1470.7759911280789,3677.1700224365045],
+ [1570.0759911280788,3511.5700224365046],
+ [1669.3759911280788,3511.5700224365046],
+ [1669.3759911280788,3677.1700224365045],
+ [1768.6759911280787,3842.7700224365044],
+ [1669.3759911280788,3842.7700224365044],
+ [1768.6759911280787,4008.3700224365043],
+ [1867.9759911280787,3842.7700224365044],
+ [1967.2759911280787,3677.1700224365045],
+ [2066.5759911280784,3842.7700224365044],
+ [2165.875991128078,3677.1700224365045],
+ [2066.5759911280784,3511.5700224365046],
+ [2165.875991128078,3511.5700224365046],
+ [2066.5759911280784,3677.1700224365045],
+ [2165.875991128078,3842.7700224365044],
+ [2265.175991128078,4008.3700224365043],
+ [2364.4759911280776,4008.3700224365043],
+ [2265.175991128078,3842.7700224365044],
+ [2364.4759911280776,3677.1700224365045],
+ [2463.7759911280773,3842.7700224365044],
+ [2463.7759911280773,4008.3700224365043],
+ [2364.4759911280776,3842.7700224365044]
+];
+
+@AssumeDynamic()
+@NoInline()
+confuse(x) => x;
+
+main() {
+ print(confuse(panels).length);
+}
diff --git a/tests/language/lazy_static7_test.dart b/tests/language/lazy_static7_test.dart
new file mode 100644
index 0000000..ff74912
--- /dev/null
+++ b/tests/language/lazy_static7_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+var sideEffect = 0;
+var x = (() { sideEffect++; return 499; })();
+
+main() {
+ if (new DateTime.now().day >= -1) {
+ x = 42;
+ }
+ Expect.equals(42, x);
+ Expect.equals(0, sideEffect);
+}
diff --git a/tests/language/many_method_calls_test.dart b/tests/language/many_method_calls_test.dart
new file mode 100644
index 0000000..25a7c89
--- /dev/null
+++ b/tests/language/many_method_calls_test.dart
@@ -0,0 +1,6644 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that compiler does not crash for very long chains of method calls.
+
+var field = false;
+
+foo() {
+ if (field) {
+ print('foo');
+ }
+}
+
+main() {
+ manyMethodCalls();
+ field = true;
+}
+
+manyMethodCalls() {
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+}
\ No newline at end of file
diff --git a/tests/language/mixin_super_bound2_test.dart b/tests/language/mixin_super_bound2_test.dart
index 543a029..87e8b7a 100644
--- a/tests/language/mixin_super_bound2_test.dart
+++ b/tests/language/mixin_super_bound2_test.dart
@@ -1,7 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--supermixin
+// SharedOptions=--supermixin
import "package:expect/expect.dart";
@@ -15,13 +15,21 @@
return false;
}
-class MS<U, V extends U> { }
+class MS<U, V
+ extends U /// 01: static type warning
+ > { }
-class M<U extends V, V> extends MS<V, U> { }
+class M<U
+ extends V /// 01: continued
+ , V> extends MS<V, U> { }
-class NS<U extends V, V> { }
+class NS<U
+ extends V /// 01: continued
+ , V> { }
-class N<U, V extends U> extends NS<V, U> { }
+class N<U, V
+ extends U /// 01: continued
+ > extends NS<V, U> { }
class S<T> { }
@@ -42,7 +50,10 @@
new MNA2<num, int, bool>();
new MNA3<num, int, bool>();
new MNA4<num, int, bool>();
- if (inCheckedMode()) {
+ bool shouldThrow = false
+ || inCheckedMode() /// 01: continued
+ ;
+ if (shouldThrow) {
// Type parameter U of M must extend type parameter V, but
// type argument List<num> is not a subtype of List<int>.
Expect.throws(() => new MNA<int, num, bool>(), (e) => e is TypeError);
diff --git a/tests/language/mixin_super_test.dart b/tests/language/mixin_super_test.dart
index 85e53e7..8a4ee98 100644
--- a/tests/language/mixin_super_test.dart
+++ b/tests/language/mixin_super_test.dart
@@ -1,7 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--supermixin
+// SharedOptions=--supermixin
import "package:expect/expect.dart";
diff --git a/tests/language/multiline_newline_cr.dart b/tests/language/multiline_newline_cr.dart
new file mode 100644
index 0000000..c5c48bc
--- /dev/null
+++ b/tests/language/multiline_newline_cr.dart
Binary files differ
diff --git a/tests/language/multiline_newline_crlf.dart b/tests/language/multiline_newline_crlf.dart
new file mode 100644
index 0000000..64cd255
--- /dev/null
+++ b/tests/language/multiline_newline_crlf.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library multiline_newline_crlf;
+
+const constantMultilineString = """
+a
+b
+""";
+
+var nonConstantMultilineString = """
+a
+b
+""";
diff --git a/tests/language/multiline_newline_lf.dart b/tests/language/multiline_newline_lf.dart
new file mode 100644
index 0000000..48b6901
--- /dev/null
+++ b/tests/language/multiline_newline_lf.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library multiline_newline_lf;
+
+const constantMultilineString = """
+a
+b
+""";
+
+var nonConstantMultilineString = """
+a
+b
+""";
diff --git a/tests/language/multiline_newline_test.dart b/tests/language/multiline_newline_test.dart
new file mode 100644
index 0000000..f250b28
--- /dev/null
+++ b/tests/language/multiline_newline_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c4 = c1 ? 1 : 2; /// 01: ok
+ Expect.equals(1, c4); /// 01: continued
+
+ const c5 = c2 ? 2 : 3; /// 02: ok
+ Expect.equals(2, c5); /// 02: continued
+
+ const c6 = c3 ? 3 : 4; /// 03: ok
+ Expect.equals(3, c6); /// 03: continued
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c10 = c7 ? 1 : 2; /// 04: compile-time error
+ const c11 = c8 ? 2 : 3; /// 05: compile-time error
+ const c12 = c9 ? 3 : 4; /// 06: compile-time error
+}
\ No newline at end of file
diff --git a/tests/language/nullaware_opt_test.dart b/tests/language/nullaware_opt_test.dart
index 05b57e8..5446171 100644
--- a/tests/language/nullaware_opt_test.dart
+++ b/tests/language/nullaware_opt_test.dart
@@ -27,7 +27,6 @@
Expect.equals(null, c?.m(bomb()));
Expect.equals(null, getNull()?.anything(bomb()));
Expect.equals(1, d?.m(1));
- Expect.equals("C", C?.toString());
Expect.equals(1, new C(1)?.f);
Expect.equals(null, c?.v);
diff --git a/tests/language/symbol_conflict_test.dart b/tests/language/symbol_conflict_test.dart
index d896c9e..10b949e 100644
--- a/tests/language/symbol_conflict_test.dart
+++ b/tests/language/symbol_conflict_test.dart
@@ -26,6 +26,13 @@
/**
The following constant was generated with the following program:
+ const RESERVED_WORDS = const [
+ 'assert', 'break', 'case', 'catch', 'class', 'const', 'continue',
+ 'default', 'do', 'else', 'enum', 'extends', 'false', 'final',
+ 'finally', 'for', 'if', 'in', 'is', 'new', 'null', 'rethrow',
+ 'return', 'super', 'switch', 'this', 'throw', 'true', 'try',
+ 'var', 'void', 'while', 'with'];
+
get chars sync* {
for (int i = "a".codeUnitAt(0); i <= "z".codeUnitAt(0); i++) {
yield new String.fromCharCodes([i]);
@@ -44,7 +51,9 @@
// Two character symbols.
for (String c1 in chars) {
for (String c2 in chars) {
- print(" const Symbol('$c1$c2'),");
+ if (!RESERVED_WORDS.contains('$c1$c2')) {
+ print(" const Symbol('$c1$c2'),");
+ }
}
}
print("];");
@@ -273,7 +282,6 @@
const Symbol('dl'),
const Symbol('dm'),
const Symbol('dn'),
- const Symbol('do'),
const Symbol('dp'),
const Symbol('dq'),
const Symbol('dr'),
@@ -524,7 +532,6 @@
const Symbol('ic'),
const Symbol('id'),
const Symbol('ie'),
- const Symbol('if'),
const Symbol('ig'),
const Symbol('ih'),
const Symbol('ii'),
@@ -532,12 +539,10 @@
const Symbol('ik'),
const Symbol('il'),
const Symbol('im'),
- const Symbol('in'),
const Symbol('io'),
const Symbol('ip'),
const Symbol('iq'),
const Symbol('ir'),
- const Symbol('is'),
const Symbol('it'),
const Symbol('iu'),
const Symbol('iv'),
diff --git a/tests/language/tearoff_basic_lib.dart b/tests/language/tearoff_basic_lib.dart
new file mode 100644
index 0000000..fe9fc07
--- /dev/null
+++ b/tests/language/tearoff_basic_lib.dart
@@ -0,0 +1,17 @@
+// 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 tearoff_basic_lib;
+
+cfunc() => "cfunc";
+
+set cset(a) { cvar = a; }
+
+get cget => "cget";
+
+var cvar = 1+2+3;
+
+final cfinvar = "set in stone";
+
+class ZZ { }
diff --git a/tests/language/tearoff_basic_test.dart b/tests/language/tearoff_basic_test.dart
new file mode 100644
index 0000000..303d38e
--- /dev/null
+++ b/tests/language/tearoff_basic_test.dart
@@ -0,0 +1,166 @@
+// 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.
+
+// Basic test for tear-off closures.
+
+import "package:expect/expect.dart";
+import "tearoff_basic_lib.dart" as P;
+import "tearoff_basic_lib.dart" deferred as D;
+
+class C {
+ var v = 99;
+ final fv = 444;
+
+ operator + (a) { return v + a; }
+ get sugus => "sugus";
+ set frosch(a) { v = "ribbit $a"; }
+ foo() => "kuh";
+
+ static var st;
+ static final stfin = 1000;
+ static stfoo([p1 = 100]) => p1 * 10;
+ static get stg => "stg";
+ static set sts(x) { st = x; }
+}
+
+
+testStatic() {
+ // Closurize static variable.
+ var a = C#st=;
+ a(100);
+ Expect.equals(100, C.st);
+ var b = C#st;
+ Expect.equals(100, b());
+
+ // Closurize static final variable.
+ a = C#stfin;
+ Expect.equals(1000, a());
+ Expect.throws(() => C#stfin= ); // Final variable has no setter.
+
+ // Closurize static method.
+ a = C#stfoo;
+ Expect.equals(1000, a());
+ Expect.equals(90, a(9));
+
+ // Closurize static getter.
+ a = C#stg;
+ Expect.equals("stg", a());
+
+ // Closurize static setter.
+ Expect.throws(() => C#sts); // No setter/method named sts exists.
+ a = C#sts=;
+ a("pflug");
+ Expect.equals("pflug", C.st);
+
+ // Can't closurize instance method via class literal.
+ Expect.throws(() => C#foo);
+
+ // Extracted closures must be equal.
+ Expect.isTrue(C#st == C#st);
+ Expect.isTrue(C#st= == C#st=);
+ Expect.isTrue(C#stfin == C#stfin);
+ Expect.isTrue(C#stfoo == C#stfoo);
+ Expect.isTrue(C#stg == C#stg);
+ Expect.isTrue(C#sts= == C#sts=);
+}
+
+testInstance() {
+ var o = new C();
+ var p = new C();
+ var a, b;
+
+ // Closurize instance variable.
+ a = o#v;
+ Expect.equals(99, a());
+ b = p#v=;
+ b(999);
+ Expect.equals(999, p.v);
+ Expect.equals(99, a());
+
+ // Closurize final instance variable.
+ Expect.throws(() => o#fv=); // Final variable has not setter.
+ a = o#fv;
+ Expect.equals(444, a());
+
+ // Closurize instance method.
+ a = o#foo;
+ Expect.equals("kuh", a());
+
+ // Closurize operator.
+ a = o#+;
+ Expect.equals(100, o + 1);
+ Expect.equals(100, a(1));
+
+ // Closurize instance getter.
+ a = o#sugus;
+ Expect.equals("sugus", a());
+ Expect.throws(() => o#sugus=);
+
+ // Closurize instance setter.
+ a = o#frosch=;
+ a("!");
+ Expect.equals("ribbit !", o.v);
+ Expect.throws(() => o#frosch);
+
+ // Extracted closures must be equal.
+ Expect.isTrue(o#v == o#v);
+ Expect.isTrue(o#v= == o#v=);
+ Expect.isTrue(o#fv == o#fv);
+ Expect.isTrue(o#foo == o#foo);
+ Expect.isTrue(o#+ == o#+);
+ Expect.isTrue(o#sugus == o#sugus);
+ Expect.isTrue(o#frosch= == o#frosch=);
+}
+
+testPrefix() {
+ // Closurize top-level variable.
+ var a = P#cvar;
+ Expect.equals(6, a());
+ var b = P#cvar=;
+ b(7);
+ Expect.equals(7, a());
+
+ // Closurize final top-level variable.
+ a = P#cfinvar;
+ Expect.equals("set in stone", a());
+ Expect.throws(() => P#cfinvar=);
+
+ // Closurize top-level function.
+ a = P#cfunc;
+ Expect.equals("cfunc", a());
+
+ // Closurize top-level getter.
+ a = P#cget;
+ Expect.equals("cget", a());
+
+ // Closurize top-level getter.
+ a = P#cset=;
+ a(99);
+ Expect.equals(99, P.cvar);
+
+ Expect.throws(() => P#ZZ); // Cannot closurize class.
+
+ // Extracted closures must be equal.
+ Expect.isTrue(P#cvar == P#cvar);
+ Expect.isTrue(P#cvar= == P#cvar=);
+ Expect.isTrue(P#cfinvar == P#cfinvar);
+ Expect.isTrue(P#cfunc == P#cfunc);
+ Expect.isTrue(P#cget == P#cget);
+ Expect.isTrue(P#cset= == P#cset=);
+}
+
+testDeferred() {
+ Expect.throws(() => D#cfunc);
+ D.loadLibrary().then((_) {
+ var a = D#cfunc;
+ Expect.equals("cfunc", a());
+ });
+}
+
+main() {
+ testStatic();
+ testInstance();
+ testPrefix();
+ testDeferred();
+}
diff --git a/tests/language/tearoff_constructor_basic_test.dart b/tests/language/tearoff_constructor_basic_test.dart
new file mode 100644
index 0000000..27c34d9
--- /dev/null
+++ b/tests/language/tearoff_constructor_basic_test.dart
@@ -0,0 +1,80 @@
+// 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.
+
+// Basic test for tear-off constructor closures.
+
+import "package:expect/expect.dart";
+
+class A {
+ // Implicit constructor A();
+ var f1 = "A.f1";
+}
+
+class P {
+ var x, y;
+ P(this.x, this.y);
+ factory P.origin() { return new P(0,0); }
+ factory P.ursprung() = P.origin;
+ P.onXAxis(x) : this(x, 0);
+}
+
+class C<T> {
+ T f1;
+ C(T p) : f1 = p;
+ C.n([T p]) : f1 = p;
+ listMaker() { return new List<T>#; } // Closurize type parameter.
+}
+
+
+testMalformed() {
+ Expect.throws(() => new NoSuchClass#);
+ Expect.throws(() => new A#noSuchContstructor);
+}
+
+testA() {
+ var cc = new A#; // Closurize implicit constructor.
+ var o = cc();
+ Expect.equals("A.f1", o.f1);
+ Expect.equals("A.f1", (new A#)().f1);
+ Expect.throws(() => new A#foo);
+}
+
+testP() {
+ var cc = new P#origin;
+ var o = cc();
+ Expect.equals(0, o.x);
+ cc = new P#ursprung;
+ o = cc();
+ Expect.equals(0, o.x);
+ cc = new P#onXAxis;
+ o = cc(5);
+ Expect.equals(0, o.y);
+ Expect.equals(5, o.x);
+ Expect.throws(() => cc(1, 1)); // Too many arguments.
+}
+
+testC() {
+ var cc = new C<int>#;
+ var o = cc(5);
+ Expect.equals("int", "${o.f1.runtimeType}");
+ Expect.throws(() => cc()); // Missing constructor parameter.
+
+ cc = new C<String>#n;
+ o = cc("foo");
+ Expect.equals("String", "${o.f1.runtimeType}");
+ o = cc();
+ Expect.equals(null, o.f1);
+
+ cc = o.listMaker();
+ Expect.isTrue(cc is Function);
+ var l = cc();
+ Expect.equals("List<String>", "${l.runtimeType}");
+}
+
+main() {
+ testA();
+ testC();
+ testP();
+ testMalformed();
+}
diff --git a/tests/lib/async/stream_type_test.dart b/tests/lib/async/stream_type_test.dart
new file mode 100644
index 0000000..a8bc2e9
--- /dev/null
+++ b/tests/lib/async/stream_type_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "package:expect/expect.dart";
+
+class TypeTest<T, NT> {
+ void call(object, name) {
+ Expect.isTrue(object is T, "$name is $T");
+ Expect.isFalse(object is NT, "$name is! $NT");
+ }
+}
+
+main() {
+ var checkIntStream = new TypeTest<Stream<int>, Stream<String>>();
+ var checkIntFuture = new TypeTest<Future<int>, Future<String>>();
+ var checkBoolFuture = new TypeTest<Future<bool>, Future<String>>();
+ var checkStringFuture = new TypeTest<Future<String>, Future<int>>();
+ var checkIntSetFuture = new TypeTest<Future<Set<int>>, Future<Set<String>>>();
+ var checkIntListFuture = new TypeTest<Future<List<int>>,
+ Future<List<String>>>();
+ var checkIntSubscription = new TypeTest<StreamSubscription<int>,
+ StreamSubscription<String>>();
+
+ // Generic function used as parameter for, e.g., `skipWhile` and `reduce`.
+ f([_1, _2]) => throw "unreachable";
+
+ bool testIntStream(stream(), name, int recursionDepth) {
+ checkIntStream(stream(), name);
+ if (recursionDepth > 0) {
+ checkIntSubscription(stream().listen(null), "$name.listen");
+
+ checkIntFuture(stream().first, "$name.first");
+ checkIntFuture(stream().last, "$name.last");
+ checkIntFuture(stream().single, "$name.single");
+ checkIntFuture(stream().singleWhere(f), "$name.singleWhere");
+ checkIntFuture(stream().elementAt(2), "$name.elementAt");
+ checkIntFuture(stream().reduce(f), "$name.reduce");
+ checkIntListFuture(stream().toList(), "$name.toList");
+ checkIntSetFuture(stream().toSet(), "$name.toSert");
+
+ checkIntFuture(stream().length, "$name.length");
+ checkBoolFuture(stream().isEmpty, "$name.is");
+ checkBoolFuture(stream().any(f) , "$name.any");
+ checkBoolFuture(stream().every(f), "$name.every");
+ checkBoolFuture(stream().contains(null), "$name.contains");
+ checkStringFuture(stream().join(), "$name.join");
+
+ var n = recursionDepth - 1;
+ testIntStream(() => stream().where(f), "$name.where", n);
+ testIntStream(() => stream().take(2), "$name.take", n);
+ testIntStream(() => stream().takeWhile(f), "$name.takeWhile", n);
+ testIntStream(() => stream().skip(2), "$name.skip", n);
+ testIntStream(() => stream().skipWhile(f), "$name.skipWhile", n);
+ testIntStream(() => stream().distinct(f), "$name.distinct", n);
+ testIntStream(() => stream().handleError(f), "$name.handleError", n);
+ testIntStream(() => stream().asBroadcastStream(),
+ "$name.asBroadcastStream", n);
+ }
+ }
+
+ testIntStream(() => new StreamController<int>().stream, "Stream<int>", 3);
+ testIntStream(() => new StreamController<int>.broadcast().stream,
+ "BroadcastStream<int>", 3);
+}
diff --git a/tests/lib/mirrors/hot_get_field_test.dart b/tests/lib/mirrors/hot_get_field_test.dart
index ca798d3..6673818 100644
--- a/tests/lib/mirrors/hot_get_field_test.dart
+++ b/tests/lib/mirrors/hot_get_field_test.dart
@@ -10,6 +10,7 @@
class C {
var field;
var _field;
+ operator +(other) => field + other;
}
const int optimizationThreshold = 20;
@@ -44,8 +45,22 @@
}
}
+testOperator() {
+ var plus = const Symbol("+");
+ var c = new C();
+ var im = reflect(c);
+
+ for (int i = 0; i < (2 * optimizationThreshold); i++) {
+ c.field = i;
+ var closurizedPlus = im.getField(plus).reflectee;
+ Expect.isTrue(closurizedPlus is Function);
+ Expect.equals(2 * i, closurizedPlus(i));
+ }
+}
+
main() {
testPublic();
testPrivate();
testPrivateWrongLibrary();
+ testOperator();
}
diff --git a/tests/lib/mirrors/io_html_mutual_exclusion_test.dart b/tests/lib/mirrors/io_html_mutual_exclusion_test.dart
new file mode 100644
index 0000000..087b8a6
--- /dev/null
+++ b/tests/lib/mirrors/io_html_mutual_exclusion_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.io_html_mutual_exclusion;
+
+import 'dart:mirrors';
+
+main() {
+ var libraries = currentMirrorSystem().libraries;
+ bool has_io = libraries[Uri.parse('dart:io')] != null;
+ bool has_html = libraries[Uri.parse('dart:html')] != null;
+
+ if (has_io && has_html) {
+ throw "No embedder should have both dart:io and dart:html accessible";
+ }
+}
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index 9ae1758..ae38307 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -42,6 +42,13 @@
Future<WebSocket> createClient(int port) =>
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/');
+ checkCloseStatus(webSocket, closeStatus, closeReason) {
+ Expect.equals(closeStatus == null ? WebSocketStatus.NO_STATUS_RECEIVED
+ : closeStatus, webSocket.closeCode);
+ Expect.equals(closeReason == null ? ""
+ : closeReason, webSocket.closeReason);
+ }
+
void testRequestResponseClientCloses(int totalConnections,
int closeStatus,
String closeReason,
@@ -55,12 +62,7 @@
webSocket.listen(
webSocket.add,
onDone: () {
- Expect.equals(closeStatus == null
- ? WebSocketStatus.NO_STATUS_RECEIVED
- : closeStatus, webSocket.closeCode);
- Expect.equals(
- closeReason == null ? ""
- : closeReason, webSocket.closeReason);
+ checkCloseStatus(webSocket, closeStatus, closeReason);
asyncEnd();
});
}, onDone: () {
@@ -85,10 +87,7 @@
}
},
onDone: () {
- Expect.equals(closeStatus == null
- ? WebSocketStatus.NO_STATUS_RECEIVED
- : closeStatus, webSocket.closeCode);
- Expect.equals("", webSocket.closeReason);
+ checkCloseStatus(webSocket, closeStatus, closeReason);
closeCount++;
if (closeCount == totalConnections) {
server.close();
@@ -119,10 +118,7 @@
}
},
onDone: () {
- Expect.equals(closeStatus == null
- ? WebSocketStatus.NO_STATUS_RECEIVED
- : closeStatus, webSocket.closeCode);
- Expect.equals("", webSocket.closeReason);
+ checkCloseStatus(webSocket, closeStatus, closeReason);
closeCount++;
if (closeCount == totalConnections) {
server.close();
@@ -136,12 +132,7 @@
webSocket.listen(
webSocket.add,
onDone: () {
- Expect.equals(closeStatus == null
- ? WebSocketStatus.NO_STATUS_RECEIVED
- : closeStatus, webSocket.closeCode);
- Expect.equals(closeReason == null
- ? ""
- : closeReason, webSocket.closeReason);
+ checkCloseStatus(webSocket, closeStatus, closeReason);
});
});
}
@@ -363,8 +354,7 @@
}
},
onDone: () {
- Expect.equals(closeStatus, webSocket.closeCode);
- Expect.equals("", webSocket.closeReason);
+ checkCloseStatus(webSocket, closeStatus, closeReason);
closeCount++;
if (closeCount == totalConnections) {
server.close();
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index c438459..f793816 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -29,6 +29,6 @@
source_mirrors_test: Pass, RuntimeError # Issue 17662
[ $compiler == dart2js && $cps_ir ]
-dummy_compiler_test: Crash # The null object does not have a getter '_element'.
-recursive_import_test: Crash # The null object does not have a getter '_element'.
-source_mirrors_test: Crash # The null object does not have a getter '_element'.
+dummy_compiler_test: Crash # (switch (function.na... continue to a labeled switch case
+recursive_import_test: Crash # (switch (function.na... continue to a labeled switch case
+source_mirrors_test: Crash # (switch (function.na... continue to a labeled switch case
diff --git a/tools/VERSION b/tools/VERSION
index c43f1ce..1800f31 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 12
PATCH 0
-PRERELEASE 4
+PRERELEASE 5
PRERELEASE_PATCH 0
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index afdbaa2..1977d7a 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -12,8 +12,8 @@
"dartium_chromium_branch": "master",
"dartium_chromium_commit": "62a7524d4f71c9e0858d24b0aa1bbff3a2d09bff",
"chromium_base_revision": "297060",
- "dartium_webkit_branch": "/blink/branches/dart/dartium",
- "dartium_webkit_revision": "198020",
+ "dartium_webkit_branch": "/blink/branches/dart/2171_3/dartium",
+ "dartium_webkit_revision": "199763",
"args_tag": "@0.13.0",
"barback_rev" : "@29ee90dbcf77cfd64632fa2797a4c8a4f29a4b51",
diff --git a/tools/gyp_dart.py b/tools/gyp_dart.py
index cce1b34..708d403 100644
--- a/tools/gyp_dart.py
+++ b/tools/gyp_dart.py
@@ -33,11 +33,6 @@
'--depth=.', '-Itools/gyp/all.gypi',
component_gyp_files[component]]
- if sys.platform == 'win32':
- # Generate Visual Studio 2010 compatible files by default.
- if not os.environ.get('GYP_MSVS_VERSION'):
- args.extend(['-G', 'msvs_version=2010'])
-
sys.exit(execute(args))
if __name__ == '__main__':
diff --git a/tools/utils.py b/tools/utils.py
index cc37f6a..2301d9b 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -97,7 +97,7 @@
# Try to guess Visual Studio location when buiding on Windows.
def GuessVisualStudioPath():
- defaultPath = r"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7" \
+ defaultPath = r"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7" \
r"\IDE"
defaultExecutable = "devenv.com"
@@ -142,8 +142,8 @@
# Can't find value under the key - continue to the next key.
continue
isExpress = executable != 'devenv.com'
- if not isExpress and subkeyName == '10.0':
- # Stop search since if we found non-Express VS2010 version
+ if not isExpress and subkeyName == '12.0':
+ # Stop search since if we found non-Express VS2013 version
# installed, which is preferred version.
return installDir, executable
else: